@reserve-protocol/dtf-cli 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1804 -314
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -2435,19 +2435,19 @@ var init_index_sdksp5px = __esm(() => {
|
|
|
2435
2435
|
__hasOwnProp = Object.prototype.hasOwnProperty;
|
|
2436
2436
|
});
|
|
2437
2437
|
|
|
2438
|
-
// ../sdk/dist/ccip-
|
|
2439
|
-
var
|
|
2440
|
-
__export(
|
|
2438
|
+
// ../sdk/dist/ccip-tn8s4j8m.js
|
|
2439
|
+
var exports_ccip_tn8s4j8m = {};
|
|
2440
|
+
__export(exports_ccip_tn8s4j8m, {
|
|
2441
2441
|
offchainLookupSignature: () => offchainLookupSignature,
|
|
2442
2442
|
offchainLookupAbiItem: () => offchainLookupAbiItem,
|
|
2443
2443
|
offchainLookup: () => offchainLookup,
|
|
2444
2444
|
ccipRequest: () => ccipRequest
|
|
2445
2445
|
});
|
|
2446
|
-
var
|
|
2447
|
-
|
|
2446
|
+
var init_ccip_tn8s4j8m = __esm(() => {
|
|
2447
|
+
init_index_azrx1hqn();
|
|
2448
2448
|
});
|
|
2449
2449
|
|
|
2450
|
-
// ../sdk/dist/index-
|
|
2450
|
+
// ../sdk/dist/index-azrx1hqn.js
|
|
2451
2451
|
function execTyped(regex, string) {
|
|
2452
2452
|
const match = regex.exec(string);
|
|
2453
2453
|
return match?.groups;
|
|
@@ -3457,6 +3457,14 @@ function hexToNumber2(hex, opts = {}) {
|
|
|
3457
3457
|
});
|
|
3458
3458
|
return number;
|
|
3459
3459
|
}
|
|
3460
|
+
function hexToString(hex, opts = {}) {
|
|
3461
|
+
let bytes = hexToBytes2(hex);
|
|
3462
|
+
if (opts.size) {
|
|
3463
|
+
assertSize3(bytes, { size: opts.size });
|
|
3464
|
+
bytes = trim3(bytes, { dir: "right" });
|
|
3465
|
+
}
|
|
3466
|
+
return new TextDecoder().decode(bytes);
|
|
3467
|
+
}
|
|
3460
3468
|
function toHex(value, opts = {}) {
|
|
3461
3469
|
if (typeof value === "number" || typeof value === "bigint")
|
|
3462
3470
|
return numberToHex(value, opts);
|
|
@@ -4795,7 +4803,7 @@ async function call(client, args) {
|
|
|
4795
4803
|
return { data: response };
|
|
4796
4804
|
} catch (err) {
|
|
4797
4805
|
const data2 = getRevertErrorData(err);
|
|
4798
|
-
const { offchainLookup: offchainLookup2, offchainLookupSignature: offchainLookupSignature2 } = await Promise.resolve().then(() => (
|
|
4806
|
+
const { offchainLookup: offchainLookup2, offchainLookupSignature: offchainLookupSignature2 } = await Promise.resolve().then(() => (init_ccip_tn8s4j8m(), exports_ccip_tn8s4j8m));
|
|
4799
4807
|
if (client.ccipRead !== false && data2?.slice(0, 10) === offchainLookupSignature2 && to)
|
|
4800
4808
|
return { data: await offchainLookup2(client, { data: data2, to }) };
|
|
4801
4809
|
if (deploylessCall && data2?.slice(0, 10) === "0x101bb98d")
|
|
@@ -5099,7 +5107,7 @@ var version = "1.2.3", BaseError, bytesRegex, integerRegex, isTupleRegex, tupleR
|
|
|
5099
5107
|
const value2 = typeof value_ === "bigint" ? value_.toString() : value_;
|
|
5100
5108
|
return typeof replacer === "function" ? replacer(key, value2) : value2;
|
|
5101
5109
|
}, space), toEventSelector, etherUnits, gweiUnits, AccountStateConflictError, StateAssignmentConflictError, InvalidLegacyVError, InvalidSerializableTransactionError, InvalidStorageKeySizeError, TransactionExecutionError, TransactionNotFoundError, TransactionReceiptNotFoundError, TransactionReceiptRevertedError, WaitForTransactionReceiptTimeoutError, getContractAddress = (address) => address, getUrl = (url) => url, CallExecutionError, ContractFunctionExecutionError, ContractFunctionRevertedError, ContractFunctionZeroDataError, CounterfactualDeploymentFailedError, RawContractError, docsPath = "/docs/contract/decodeFunctionResult", docsPath2 = "/docs/contract/encodeDeployData", docsPath3 = "/docs/contract/encodeFunctionData", ExecutionRevertedError, FeeCapTooHighError, FeeCapTooLowError, NonceTooHighError, NonceTooLowError, NonceMaxValueError, InsufficientFundsError, IntrinsicGasTooHighError, IntrinsicGasTooLowError, TransactionTypeNotSupportedError, TipAboveFeeCapError, UnknownNodeError, HttpRequestError, RpcRequestError, TimeoutError, unknownErrorCode = -1, RpcError, ProviderRpcError, ParseRpcError, InvalidRequestRpcError, MethodNotFoundRpcError, InvalidParamsRpcError, InternalRpcError, InvalidInputRpcError, ResourceNotFoundRpcError, ResourceUnavailableRpcError, TransactionRejectedRpcError, MethodNotSupportedRpcError, LimitExceededRpcError, JsonRpcVersionUnsupportedError, UserRejectedRequestError, UnauthorizedProviderError, UnsupportedProviderMethodError, ProviderDisconnectedError, ChainDisconnectedError, SwitchChainError, UnsupportedNonOptionalCapabilityError, UnsupportedChainIdError, DuplicateIdError, UnknownBundleIdError, BundleTooLargeError, AtomicReadyWalletRejectedUpgradeError, AtomicityNotSupportedError, WalletConnectSessionSettlementError, UnknownRpcError, rpcTransactionType, schedulerCache, maxInt8, maxInt16, maxInt24, maxInt32, maxInt40, maxInt48, maxInt56, maxInt64, maxInt72, maxInt80, maxInt88, maxInt96, maxInt104, maxInt112, maxInt120, maxInt128, maxInt136, maxInt144, maxInt152, maxInt160, maxInt168, maxInt176, maxInt184, maxInt192, maxInt200, maxInt208, maxInt216, maxInt224, maxInt232, maxInt240, maxInt248, maxInt256, minInt8, minInt16, minInt24, minInt32, minInt40, minInt48, minInt56, minInt64, minInt72, minInt80, minInt88, minInt96, minInt104, minInt112, minInt120, minInt128, minInt136, minInt144, minInt152, minInt160, minInt168, minInt176, minInt184, minInt192, minInt200, minInt208, minInt216, minInt224, minInt232, minInt240, minInt248, minInt256, maxUint8, maxUint16, maxUint24, maxUint32, maxUint40, maxUint48, maxUint56, maxUint64, maxUint72, maxUint80, maxUint88, maxUint96, maxUint104, maxUint112, maxUint120, maxUint128, maxUint136, maxUint144, maxUint152, maxUint160, maxUint168, maxUint176, maxUint184, maxUint192, maxUint200, maxUint208, maxUint216, maxUint224, maxUint232, maxUint240, maxUint248, maxUint256, OffchainLookupError, OffchainLookupResponseMalformedError, OffchainLookupSenderMismatchError, docsPath4 = "/docs/contract/encodeErrorResult", docsPath5 = "/docs/contract/encodeFunctionResult", localBatchGatewayUrl = "x-batch-gateway:true", offchainLookupSignature = "0x556f1830", offchainLookupAbiItem;
|
|
5102
|
-
var
|
|
5110
|
+
var init_index_azrx1hqn = __esm(() => {
|
|
5103
5111
|
init_index_wjqsw4fc();
|
|
5104
5112
|
BaseError = class BaseError extends Error {
|
|
5105
5113
|
constructor(shortMessage, args = {}) {
|
|
@@ -8952,6 +8960,8 @@ function resolveConfig(args) {
|
|
|
8952
8960
|
const limitStr = getFlag(args, "--limit");
|
|
8953
8961
|
const limit = limitStr !== undefined ? Number(limitStr) : undefined;
|
|
8954
8962
|
const performance = getFlag(args, "--performance") ?? undefined;
|
|
8963
|
+
const subgraphRaw = getFlag(args, "--subgraph");
|
|
8964
|
+
const subgraph = subgraphRaw === "index" || subgraphRaw === "yield" ? subgraphRaw : undefined;
|
|
8955
8965
|
return {
|
|
8956
8966
|
chainId: Number(chainId),
|
|
8957
8967
|
allChains,
|
|
@@ -8964,7 +8974,8 @@ function resolveConfig(args) {
|
|
|
8964
8974
|
account,
|
|
8965
8975
|
nonce,
|
|
8966
8976
|
limit,
|
|
8967
|
-
performance
|
|
8977
|
+
performance,
|
|
8978
|
+
subgraph
|
|
8968
8979
|
};
|
|
8969
8980
|
}
|
|
8970
8981
|
function getCommand(args) {
|
|
@@ -8972,7 +8983,7 @@ function getCommand(args) {
|
|
|
8972
8983
|
let i = 0;
|
|
8973
8984
|
while (i < args.length) {
|
|
8974
8985
|
const arg = args[i];
|
|
8975
|
-
if (arg === "--chain" || arg === "--rpc" || arg === "--wallet-key" || arg === "--action" || arg === "--account" || arg === "--nonce" || arg === "--limit" || arg === "--performance" || arg === "--name" || arg === "--symbol" || arg === "--basket" || arg === "--amount" || arg === "--config" || arg === "--mandate") {
|
|
8986
|
+
if (arg === "--chain" || arg === "--rpc" || arg === "--wallet-key" || arg === "--action" || arg === "--account" || arg === "--nonce" || arg === "--limit" || arg === "--performance" || arg === "--name" || arg === "--symbol" || arg === "--basket" || arg === "--amount" || arg === "--config" || arg === "--mandate" || arg === "--subgraph") {
|
|
8976
8987
|
i += 2;
|
|
8977
8988
|
} else if (arg === "--json" || arg === "--help" || arg === "--all" || arg === "--dry-run" || arg === "--ungoverned" || arg === "--list-tokens") {
|
|
8978
8989
|
i++;
|
|
@@ -9006,37 +9017,49 @@ function loadRcFile() {
|
|
|
9006
9017
|
|
|
9007
9018
|
// src/lib/dtf-registry.ts
|
|
9008
9019
|
var REGISTRY = [
|
|
9009
|
-
{ symbol: "CMC20", name: "CoinMarketCap 20 Index DTF", address: "0x2f8a339b5889ffac4c5a956787cda593b3c36867", chainId: 56 },
|
|
9010
|
-
{ symbol: "LCAP", name: "CF Large Cap Index", address: "0x4da9a0f397db1397902070f93a4d6ddbc0e0e6e8", chainId: 8453 },
|
|
9011
|
-
{ symbol: "VLONE", name: "Reserve Venionaire L1 Select DTF", address: "0xe00cfa595841fb331105b93c19827797c925e3e4", chainId: 8453 },
|
|
9012
|
-
{ symbol: "BGCI", name: "Bloomberg Galaxy Crypto Index", address: "0x23418de10d422ad71c9d5713a2b8991a9c586443", chainId: 8453 },
|
|
9013
|
-
{ symbol: "ABX", name: "Alpha Base Index", address: "0xebcda5b80f62dd4dd2a96357b42bb6facbf30267", chainId: 8453 },
|
|
9014
|
-
{ symbol: "OPEN", name: "Open Stablecoin Index", address: "0x323c03c48660fe31186fa82c289b0766d331ce21", chainId: 1 },
|
|
9015
|
-
{ symbol: "CLX", name: "Clanker Index", address: "0x44551ca46fa5592bb572e20043f7c3d54c85cad7", chainId: 8453 },
|
|
9016
|
-
{ symbol: "BED", name: "BTC ETH DCA Index", address: "0x4e3b170dcbe704b248df5f56d488114ace01b1c5", chainId: 1 },
|
|
9017
|
-
{ symbol: "SMEL", name: "Imagine The SMEL", address: "0xf91384484f4717314798e8975bcd904a35fc2bf1", chainId: 1 },
|
|
9018
|
-
{ symbol: "MVTT10F", name: "MarketVector Token Terminal", address: "0xe8b46b116d3bdfa787ce9cf3f5acc78dc7ca380e", chainId: 8453 },
|
|
9019
|
-
{ symbol: "ixEdel", name: "Sagix Club Edelweiss", address: "0xe4a10951f962e6cb93cb843a4ef05d2f99db1f94", chainId: 1 },
|
|
9020
|
-
{ symbol: "DGI", name: "DeFi Growth Index", address: "0x9a1741e151233a82cf69209a2f1bc7442b1fb29c", chainId: 1 },
|
|
9021
|
-
{ symbol: "DFX", name: "CoinDesk DeFi Select Index", address: "0x188d12eb13a5eadd0867074ce8354b1ad6f4790b", chainId: 1 },
|
|
9022
|
-
{ symbol: "mvRWA", name: "RWA Index", address: "0xa5cdea03b11042fc10b52af9eca48bb17a2107d2", chainId: 1 },
|
|
9023
|
-
{ symbol: "mvDEFI", name: "Large Cap DeFi Index", address: "0x20d81101d254729a6e689418526be31e2c544290", chainId: 1 },
|
|
9024
|
-
{ symbol: "AI", name: "AIndex", address: "0xfe45eda533e97198d9f3deeda9ae6c147141f6f9", chainId: 8453 },
|
|
9025
|
-
{ symbol: "VTF", name: "Virtuals Index", address: "0x47686106181b3cefe4eaf94c4c10b48ac750370b", chainId: 8453 },
|
|
9026
|
-
{ symbol: "ZINDEX", name: "Zora Index", address: "0x160c18476f6f5099f374033fbc695c9234cda495", chainId: 8453 },
|
|
9027
|
-
{ symbol: "BDTF", name: "Base MemeIndexer DTF", address: "0xb8753941196692e322846cfee9c14c97ac81928a", chainId: 8453 },
|
|
9028
|
-
{ symbol: "CLUB", name: "Club Night DTF", address: "0xf8ef6e785473e82527908b06023ac3e401ccfdcd", chainId: 8453 },
|
|
9029
|
-
{ symbol: "MVDA25", name: "MarketVector Digital Assets 25", address: "0xd600e748c17ca237fcb5967fa13d688aff17be78", chainId: 8453 },
|
|
9030
|
-
{ symbol: "SBR", name: "Strategic Base Reserve", address: "0x89ff8f639d402839205a6bf03cc01bdffa4768b7", chainId: 8453 }
|
|
9020
|
+
{ symbol: "CMC20", name: "CoinMarketCap 20 Index DTF", address: "0x2f8a339b5889ffac4c5a956787cda593b3c36867", chainId: 56, type: "index" },
|
|
9021
|
+
{ symbol: "LCAP", name: "CF Large Cap Index", address: "0x4da9a0f397db1397902070f93a4d6ddbc0e0e6e8", chainId: 8453, type: "index" },
|
|
9022
|
+
{ symbol: "VLONE", name: "Reserve Venionaire L1 Select DTF", address: "0xe00cfa595841fb331105b93c19827797c925e3e4", chainId: 8453, type: "index" },
|
|
9023
|
+
{ symbol: "BGCI", name: "Bloomberg Galaxy Crypto Index", address: "0x23418de10d422ad71c9d5713a2b8991a9c586443", chainId: 8453, type: "index" },
|
|
9024
|
+
{ symbol: "ABX", name: "Alpha Base Index", address: "0xebcda5b80f62dd4dd2a96357b42bb6facbf30267", chainId: 8453, type: "index" },
|
|
9025
|
+
{ symbol: "OPEN", name: "Open Stablecoin Index", address: "0x323c03c48660fe31186fa82c289b0766d331ce21", chainId: 1, type: "index" },
|
|
9026
|
+
{ symbol: "CLX", name: "Clanker Index", address: "0x44551ca46fa5592bb572e20043f7c3d54c85cad7", chainId: 8453, type: "index" },
|
|
9027
|
+
{ symbol: "BED", name: "BTC ETH DCA Index", address: "0x4e3b170dcbe704b248df5f56d488114ace01b1c5", chainId: 1, type: "index" },
|
|
9028
|
+
{ symbol: "SMEL", name: "Imagine The SMEL", address: "0xf91384484f4717314798e8975bcd904a35fc2bf1", chainId: 1, type: "index" },
|
|
9029
|
+
{ symbol: "MVTT10F", name: "MarketVector Token Terminal", address: "0xe8b46b116d3bdfa787ce9cf3f5acc78dc7ca380e", chainId: 8453, type: "index" },
|
|
9030
|
+
{ symbol: "ixEdel", name: "Sagix Club Edelweiss", address: "0xe4a10951f962e6cb93cb843a4ef05d2f99db1f94", chainId: 1, type: "index" },
|
|
9031
|
+
{ symbol: "DGI", name: "DeFi Growth Index", address: "0x9a1741e151233a82cf69209a2f1bc7442b1fb29c", chainId: 1, type: "index" },
|
|
9032
|
+
{ symbol: "DFX", name: "CoinDesk DeFi Select Index", address: "0x188d12eb13a5eadd0867074ce8354b1ad6f4790b", chainId: 1, type: "index" },
|
|
9033
|
+
{ symbol: "mvRWA", name: "RWA Index", address: "0xa5cdea03b11042fc10b52af9eca48bb17a2107d2", chainId: 1, type: "index" },
|
|
9034
|
+
{ symbol: "mvDEFI", name: "Large Cap DeFi Index", address: "0x20d81101d254729a6e689418526be31e2c544290", chainId: 1, type: "index" },
|
|
9035
|
+
{ symbol: "AI", name: "AIndex", address: "0xfe45eda533e97198d9f3deeda9ae6c147141f6f9", chainId: 8453, type: "index" },
|
|
9036
|
+
{ symbol: "VTF", name: "Virtuals Index", address: "0x47686106181b3cefe4eaf94c4c10b48ac750370b", chainId: 8453, type: "index" },
|
|
9037
|
+
{ symbol: "ZINDEX", name: "Zora Index", address: "0x160c18476f6f5099f374033fbc695c9234cda495", chainId: 8453, type: "index" },
|
|
9038
|
+
{ symbol: "BDTF", name: "Base MemeIndexer DTF", address: "0xb8753941196692e322846cfee9c14c97ac81928a", chainId: 8453, type: "index" },
|
|
9039
|
+
{ symbol: "CLUB", name: "Club Night DTF", address: "0xf8ef6e785473e82527908b06023ac3e401ccfdcd", chainId: 8453, type: "index" },
|
|
9040
|
+
{ symbol: "MVDA25", name: "MarketVector Digital Assets 25", address: "0xd600e748c17ca237fcb5967fa13d688aff17be78", chainId: 8453, type: "index" },
|
|
9041
|
+
{ symbol: "SBR", name: "Strategic Base Reserve", address: "0x89ff8f639d402839205a6bf03cc01bdffa4768b7", chainId: 8453, type: "index" },
|
|
9042
|
+
{ symbol: "dgnETH", name: "Degen ETH", address: "0x005F893EcD7bF9667195642f7649DA8163e23658", chainId: 1, type: "yield" },
|
|
9043
|
+
{ symbol: "eUSD", name: "Electronic Dollar", address: "0xA0d69E286B938e21CBf7E51D71F6A4c8918f482F", chainId: 1, type: "yield" },
|
|
9044
|
+
{ symbol: "ETH+", name: "ETHPlus", address: "0xE72B141DF173b999AE7c1aDcbF60Cc9833Ce56a8", chainId: 1, type: "yield" },
|
|
9045
|
+
{ symbol: "hyUSD", name: "High Yield USD", address: "0xaCdf0DBA4B9839b96221a8487e9ca660a48212be", chainId: 1, type: "yield" },
|
|
9046
|
+
{ symbol: "USDC+", name: "USDC Plus", address: "0xFc0B1EEf20e4c68B3DCF36c4537Cfa7Ce46CA70b", chainId: 1, type: "yield" },
|
|
9047
|
+
{ symbol: "USD3", name: "Web 3 Dollar", address: "0x0d86883FAf4FfD7aEb116390af37746F45b6f378", chainId: 1, type: "yield" },
|
|
9048
|
+
{ symbol: "rgUSD", name: "Revenue Generating USD", address: "0x78da5799CF427Fee11e9996982F4150eCe7a99A7", chainId: 1, type: "yield" },
|
|
9049
|
+
{ symbol: "hyUSD", name: "High Yield USD", address: "0xCc7FF230365bD730eE4B352cC2492CEdAC49383e", chainId: 8453, type: "yield" },
|
|
9050
|
+
{ symbol: "BSDX", name: "Base Yield Index", address: "0x8f0987DDb485219c767770e2080E5cC01ddc772a", chainId: 8453, type: "yield" },
|
|
9051
|
+
{ symbol: "bsdETH", name: "Based ETH", address: "0xCb327b99fF831bF8223cCEd12B1338FF3aA322Ff", chainId: 8453, type: "yield" },
|
|
9052
|
+
{ symbol: "Vaya", name: "Vaya", address: "0xC9a3e2B3064c1c0546D3D0edc0A748E9f93Cf18d", chainId: 8453, type: "yield" },
|
|
9053
|
+
{ symbol: "MAAT", name: "Maat", address: "0x641B0453487C9D14c5df96d45a481ef1dc84e31f", chainId: 8453, type: "yield" }
|
|
9031
9054
|
];
|
|
9032
9055
|
function resolveAlias(input) {
|
|
9033
9056
|
const lower = input.toLowerCase();
|
|
9034
9057
|
const bySymbol = REGISTRY.find((d) => d.symbol.toLowerCase() === lower);
|
|
9035
9058
|
if (bySymbol)
|
|
9036
|
-
return { address: bySymbol.address, chainId: bySymbol.chainId };
|
|
9059
|
+
return { address: bySymbol.address, chainId: bySymbol.chainId, type: bySymbol.type };
|
|
9037
9060
|
const nameMatches = REGISTRY.filter((d) => d.name.toLowerCase().includes(lower));
|
|
9038
9061
|
if (nameMatches.length === 1) {
|
|
9039
|
-
return { address: nameMatches[0].address, chainId: nameMatches[0].chainId };
|
|
9062
|
+
return { address: nameMatches[0].address, chainId: nameMatches[0].chainId, type: nameMatches[0].type };
|
|
9040
9063
|
}
|
|
9041
9064
|
if (nameMatches.length > 1) {
|
|
9042
9065
|
return {
|
|
@@ -9049,6 +9072,10 @@ function resolveAlias(input) {
|
|
|
9049
9072
|
}
|
|
9050
9073
|
return null;
|
|
9051
9074
|
}
|
|
9075
|
+
function getRegistryType(address) {
|
|
9076
|
+
const lower = address.toLowerCase();
|
|
9077
|
+
return REGISTRY.find((d) => d.address.toLowerCase() === lower)?.type;
|
|
9078
|
+
}
|
|
9052
9079
|
|
|
9053
9080
|
// src/lib/cache.ts
|
|
9054
9081
|
import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, writeFileSync, rmSync } from "fs";
|
|
@@ -9104,7 +9131,7 @@ function setCache(chainId, address, data) {
|
|
|
9104
9131
|
|
|
9105
9132
|
// ../sdk/dist/index.js
|
|
9106
9133
|
init_index_qp8fkhx7();
|
|
9107
|
-
|
|
9134
|
+
init_index_azrx1hqn();
|
|
9108
9135
|
init_index_sdksp5px();
|
|
9109
9136
|
var require_types = __commonJS((exports) => {
|
|
9110
9137
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -19505,6 +19532,14 @@ var SUBGRAPH_URLS = {
|
|
|
19505
19532
|
56: "https://api.goldsky.com/api/public/project_cmgzim3e100095np2gjnbh6ry/subgraphs/dtf-index-bsc/prod/gn",
|
|
19506
19533
|
8453: "https://api.goldsky.com/api/public/project_cmgzim3e100095np2gjnbh6ry/subgraphs/dtf-index-base/prod/gn"
|
|
19507
19534
|
};
|
|
19535
|
+
var YIELD_SUBGRAPH_URLS = {
|
|
19536
|
+
1: "https://api.goldsky.com/api/public/project_cmgzim3e100095np2gjnbh6ry/subgraphs/dtf-yield-mainnet/4.2.0-v2/gn",
|
|
19537
|
+
8453: "https://api.goldsky.com/api/public/project_cmgzim3e100095np2gjnbh6ry/subgraphs/dtf-yield-base/4.2.0-v2/gn"
|
|
19538
|
+
};
|
|
19539
|
+
var FACADE_READ_ADDRESS = {
|
|
19540
|
+
1: "0x2C7ca56342177343A2954C250702Fd464f4d0613",
|
|
19541
|
+
8453: "0xeb2071e9b542555e90e6e4e1f83fa17423583991"
|
|
19542
|
+
};
|
|
19508
19543
|
var SUPPORTED_CHAINS = [1, 56, 8453];
|
|
19509
19544
|
var CHAINLINK_BTC_USD = "0xF4030086522a5bEEa4988F8cA5B36dbC97BeE88c";
|
|
19510
19545
|
var CHAINLINK_RSR_USD = "0x759bBC1be8F90eE6457C44abc7d443842a976d02";
|
|
@@ -19600,11 +19635,11 @@ async function fetchWithRetry(url, init, opts) {
|
|
|
19600
19635
|
}
|
|
19601
19636
|
throw lastError;
|
|
19602
19637
|
}
|
|
19603
|
-
async function querySubgraph(chainId, query, variables = {}) {
|
|
19604
|
-
const
|
|
19605
|
-
if (!
|
|
19638
|
+
async function querySubgraph(chainId, query, variables = {}, url) {
|
|
19639
|
+
const endpoint = url ?? SUBGRAPH_URLS[chainId];
|
|
19640
|
+
if (!endpoint)
|
|
19606
19641
|
throw new Error(`No subgraph URL for chainId ${chainId}`);
|
|
19607
|
-
const response = await fetchWithRetry(
|
|
19642
|
+
const response = await fetchWithRetry(endpoint, {
|
|
19608
19643
|
method: "POST",
|
|
19609
19644
|
headers: { "Content-Type": "application/json" },
|
|
19610
19645
|
body: JSON.stringify({ query, variables })
|
|
@@ -21176,240 +21211,705 @@ async function fetchVoteLockPositions(baseUrl = RESERVE_API_BASE_URL) {
|
|
|
21176
21211
|
}
|
|
21177
21212
|
return await response.json();
|
|
21178
21213
|
}
|
|
21179
|
-
|
|
21180
|
-
const results = await publicClient.multicall({
|
|
21181
|
-
contracts: [
|
|
21182
|
-
{
|
|
21183
|
-
address: folioAddress,
|
|
21184
|
-
abi: folio_default,
|
|
21185
|
-
functionName: "toAssets",
|
|
21186
|
-
args: [shares, 1]
|
|
21187
|
-
},
|
|
21188
|
-
{
|
|
21189
|
-
address: folioAddress,
|
|
21190
|
-
abi: folio_default,
|
|
21191
|
-
functionName: "mintFee"
|
|
21192
|
-
}
|
|
21193
|
-
]
|
|
21194
|
-
});
|
|
21195
|
-
if (results[0].status !== "success")
|
|
21196
|
-
throw new Error(`toAssets failed for ${folioAddress} with ${shares} shares`);
|
|
21197
|
-
if (results[1].status !== "success")
|
|
21198
|
-
throw new Error(`mintFee failed for ${folioAddress}`);
|
|
21199
|
-
const [assets, amounts] = results[0].result;
|
|
21200
|
-
const mintFee = results[1].result;
|
|
21201
|
-
const minSharesOut = shares - shares * mintFee / D18;
|
|
21202
|
-
return { shares, assets, amounts, mintFee, minSharesOut };
|
|
21203
|
-
}
|
|
21204
|
-
async function readMintFee(publicClient, folioAddress) {
|
|
21205
|
-
return await publicClient.readContract({
|
|
21206
|
-
address: folioAddress,
|
|
21207
|
-
abi: folio_default,
|
|
21208
|
-
functionName: "mintFee"
|
|
21209
|
-
});
|
|
21210
|
-
}
|
|
21211
|
-
function applySlippage(amount, slippageBps) {
|
|
21212
|
-
if (slippageBps < 0n || slippageBps > 10000n) {
|
|
21213
|
-
throw new Error(`slippageBps must be between 0 and 10000, got ${slippageBps}`);
|
|
21214
|
-
}
|
|
21215
|
-
return amount - amount * slippageBps / 10000n;
|
|
21216
|
-
}
|
|
21217
|
-
async function readRedeemQuote(publicClient, folioAddress, shares) {
|
|
21218
|
-
const result = await publicClient.readContract({
|
|
21219
|
-
address: folioAddress,
|
|
21220
|
-
abi: folio_default,
|
|
21221
|
-
functionName: "toAssets",
|
|
21222
|
-
args: [shares, 0]
|
|
21223
|
-
});
|
|
21224
|
-
const [assets, amounts] = result;
|
|
21225
|
-
return { shares, assets, amounts };
|
|
21226
|
-
}
|
|
21227
|
-
async function readPendingFees(publicClient, folioAddress) {
|
|
21228
|
-
const results = await publicClient.multicall({
|
|
21229
|
-
contracts: [
|
|
21230
|
-
{
|
|
21231
|
-
address: folioAddress,
|
|
21232
|
-
abi: folio_default,
|
|
21233
|
-
functionName: "getPendingFeeShares"
|
|
21234
|
-
},
|
|
21235
|
-
{
|
|
21236
|
-
address: folioAddress,
|
|
21237
|
-
abi: folio_default,
|
|
21238
|
-
functionName: "feeRecipientsPendingFeeShares"
|
|
21239
|
-
},
|
|
21240
|
-
{
|
|
21241
|
-
address: folioAddress,
|
|
21242
|
-
abi: folio_default,
|
|
21243
|
-
functionName: "daoPendingFeeShares"
|
|
21244
|
-
}
|
|
21245
|
-
]
|
|
21246
|
-
});
|
|
21247
|
-
const total = results[0].status === "success" ? results[0].result : 0n;
|
|
21248
|
-
const folio = results[1].status === "success" ? results[1].result : 0n;
|
|
21249
|
-
const dao = results[2].status === "success" ? results[2].result : 0n;
|
|
21250
|
-
return { total, folio, dao };
|
|
21251
|
-
}
|
|
21252
|
-
async function readFeeRecipients(publicClient, folioAddress) {
|
|
21253
|
-
const indices = Array.from({ length: 10 }, (_, i) => i);
|
|
21254
|
-
const results = await publicClient.multicall({
|
|
21255
|
-
contracts: indices.map((i) => ({
|
|
21256
|
-
address: folioAddress,
|
|
21257
|
-
abi: folio_default,
|
|
21258
|
-
functionName: "feeRecipients",
|
|
21259
|
-
args: [BigInt(i)]
|
|
21260
|
-
}))
|
|
21261
|
-
});
|
|
21262
|
-
const recipients = [];
|
|
21263
|
-
for (const r of results) {
|
|
21264
|
-
if (r.status !== "success")
|
|
21265
|
-
break;
|
|
21266
|
-
const [recipient, portion] = r.result;
|
|
21267
|
-
recipients.push({ recipient, portion });
|
|
21268
|
-
}
|
|
21269
|
-
return recipients;
|
|
21270
|
-
}
|
|
21271
|
-
async function fetchRebalanceHistory(chainId, folioAddress, opts, baseUrl = RESERVE_API_BASE_URL) {
|
|
21272
|
-
const skip = opts?.skip ?? 0;
|
|
21273
|
-
const limit = opts?.limit ?? 50;
|
|
21274
|
-
const url = `${baseUrl}/dtf/rebalance?address=${folioAddress.toLowerCase()}&chainId=${chainId}&skip=${skip}&limit=${limit}`;
|
|
21275
|
-
const response = await fetchWithRetry(url);
|
|
21276
|
-
if (!response.ok) {
|
|
21277
|
-
throw new Error(`Reserve API /dtf/rebalance failed: ${response.status} ${response.statusText}`);
|
|
21278
|
-
}
|
|
21279
|
-
return await response.json();
|
|
21280
|
-
}
|
|
21281
|
-
async function fetchRebalanceDetail(chainId, folioAddress, nonce, baseUrl = RESERVE_API_BASE_URL) {
|
|
21282
|
-
const url = `${baseUrl}/dtf/rebalance?address=${folioAddress.toLowerCase()}&chainId=${chainId}&nonce=${nonce}`;
|
|
21283
|
-
const response = await fetchWithRetry(url);
|
|
21284
|
-
if (!response.ok) {
|
|
21285
|
-
throw new Error(`Reserve API /dtf/rebalance detail failed: ${response.status} ${response.statusText}`);
|
|
21286
|
-
}
|
|
21287
|
-
return await response.json();
|
|
21288
|
-
}
|
|
21289
|
-
async function fetchHistoricalDtf(chainId, folioAddress, opts, baseUrl = RESERVE_API_BASE_URL) {
|
|
21290
|
-
const now = Math.floor(Date.now() / 1000);
|
|
21291
|
-
const to = opts?.to ?? now;
|
|
21292
|
-
const from14 = opts?.from ?? to - 2592000;
|
|
21293
|
-
const interval = opts?.interval ?? "1h";
|
|
21294
|
-
const url = `${baseUrl}/historical/dtf?address=${folioAddress.toLowerCase()}&chainId=${chainId}&from=${from14}&to=${to}&interval=${interval}`;
|
|
21295
|
-
const response = await fetchWithRetry(url);
|
|
21296
|
-
if (!response.ok) {
|
|
21297
|
-
throw new Error(`Reserve API /historical/dtf failed: ${response.status} ${response.statusText}`);
|
|
21298
|
-
}
|
|
21299
|
-
const data = await response.json();
|
|
21300
|
-
if (Array.isArray(data))
|
|
21301
|
-
return data;
|
|
21302
|
-
return data.timeseries ?? [];
|
|
21303
|
-
}
|
|
21304
|
-
var governor_default = [
|
|
21214
|
+
var stRSRAbi = [
|
|
21305
21215
|
{
|
|
21306
|
-
type: "constructor",
|
|
21307
21216
|
inputs: [],
|
|
21308
|
-
|
|
21217
|
+
name: "exchangeRate",
|
|
21218
|
+
outputs: [{ internalType: "uint192", name: "", type: "uint192" }],
|
|
21219
|
+
stateMutability: "view",
|
|
21220
|
+
type: "function"
|
|
21309
21221
|
},
|
|
21310
21222
|
{
|
|
21311
|
-
|
|
21312
|
-
|
|
21223
|
+
inputs: [],
|
|
21224
|
+
name: "totalSupply",
|
|
21225
|
+
outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
|
|
21226
|
+
stateMutability: "view",
|
|
21227
|
+
type: "function"
|
|
21313
21228
|
},
|
|
21314
21229
|
{
|
|
21315
|
-
type: "function",
|
|
21316
|
-
name: "BALLOT_TYPEHASH",
|
|
21317
21230
|
inputs: [],
|
|
21318
|
-
|
|
21319
|
-
|
|
21320
|
-
|
|
21321
|
-
|
|
21322
|
-
|
|
21323
|
-
|
|
21231
|
+
name: "unstakingDelay",
|
|
21232
|
+
outputs: [{ internalType: "uint48", name: "", type: "uint48" }],
|
|
21233
|
+
stateMutability: "view",
|
|
21234
|
+
type: "function"
|
|
21235
|
+
},
|
|
21236
|
+
{
|
|
21237
|
+
inputs: [
|
|
21238
|
+
{ internalType: "address", name: "account", type: "address" }
|
|
21324
21239
|
],
|
|
21325
|
-
|
|
21240
|
+
name: "balanceOf",
|
|
21241
|
+
outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
|
|
21242
|
+
stateMutability: "view",
|
|
21243
|
+
type: "function"
|
|
21326
21244
|
},
|
|
21327
21245
|
{
|
|
21328
|
-
type: "function",
|
|
21329
|
-
name: "CLOCK_MODE",
|
|
21330
21246
|
inputs: [],
|
|
21331
|
-
|
|
21332
|
-
|
|
21333
|
-
|
|
21334
|
-
|
|
21335
|
-
internalType: "string"
|
|
21336
|
-
}
|
|
21337
|
-
],
|
|
21338
|
-
stateMutability: "view"
|
|
21247
|
+
name: "main",
|
|
21248
|
+
outputs: [{ internalType: "contract IMain", name: "", type: "address" }],
|
|
21249
|
+
stateMutability: "view",
|
|
21250
|
+
type: "function"
|
|
21339
21251
|
},
|
|
21340
21252
|
{
|
|
21341
|
-
type: "function",
|
|
21342
|
-
name: "COUNTING_MODE",
|
|
21343
21253
|
inputs: [],
|
|
21344
|
-
|
|
21345
|
-
|
|
21346
|
-
|
|
21347
|
-
|
|
21348
|
-
internalType: "string"
|
|
21349
|
-
}
|
|
21350
|
-
],
|
|
21351
|
-
stateMutability: "pure"
|
|
21254
|
+
name: "name",
|
|
21255
|
+
outputs: [{ internalType: "string", name: "", type: "string" }],
|
|
21256
|
+
stateMutability: "view",
|
|
21257
|
+
type: "function"
|
|
21352
21258
|
},
|
|
21353
21259
|
{
|
|
21354
|
-
type: "function",
|
|
21355
|
-
name: "EXTENDED_BALLOT_TYPEHASH",
|
|
21356
21260
|
inputs: [],
|
|
21357
|
-
|
|
21358
|
-
|
|
21359
|
-
|
|
21360
|
-
|
|
21361
|
-
internalType: "bytes32"
|
|
21362
|
-
}
|
|
21363
|
-
],
|
|
21364
|
-
stateMutability: "view"
|
|
21261
|
+
name: "symbol",
|
|
21262
|
+
outputs: [{ internalType: "string", name: "", type: "string" }],
|
|
21263
|
+
stateMutability: "view",
|
|
21264
|
+
type: "function"
|
|
21365
21265
|
},
|
|
21366
21266
|
{
|
|
21367
|
-
type: "function",
|
|
21368
|
-
name: "cancel",
|
|
21369
21267
|
inputs: [
|
|
21370
|
-
{
|
|
21371
|
-
name: "targets",
|
|
21372
|
-
type: "address[]",
|
|
21373
|
-
internalType: "address[]"
|
|
21374
|
-
},
|
|
21375
|
-
{
|
|
21376
|
-
name: "values",
|
|
21377
|
-
type: "uint256[]",
|
|
21378
|
-
internalType: "uint256[]"
|
|
21379
|
-
},
|
|
21380
|
-
{
|
|
21381
|
-
name: "calldatas",
|
|
21382
|
-
type: "bytes[]",
|
|
21383
|
-
internalType: "bytes[]"
|
|
21384
|
-
},
|
|
21385
|
-
{
|
|
21386
|
-
name: "descriptionHash",
|
|
21387
|
-
type: "bytes32",
|
|
21388
|
-
internalType: "bytes32"
|
|
21389
|
-
}
|
|
21390
|
-
],
|
|
21391
|
-
outputs: [
|
|
21392
|
-
{
|
|
21393
|
-
name: "",
|
|
21394
|
-
type: "uint256",
|
|
21395
|
-
internalType: "uint256"
|
|
21396
|
-
}
|
|
21268
|
+
{ internalType: "address", name: "account", type: "address" }
|
|
21397
21269
|
],
|
|
21398
|
-
|
|
21270
|
+
name: "delegates",
|
|
21271
|
+
outputs: [{ internalType: "address", name: "", type: "address" }],
|
|
21272
|
+
stateMutability: "view",
|
|
21273
|
+
type: "function"
|
|
21399
21274
|
},
|
|
21400
21275
|
{
|
|
21401
|
-
type: "function",
|
|
21402
|
-
name: "castVote",
|
|
21403
21276
|
inputs: [
|
|
21404
|
-
{
|
|
21405
|
-
|
|
21406
|
-
|
|
21407
|
-
|
|
21408
|
-
|
|
21409
|
-
|
|
21410
|
-
|
|
21411
|
-
|
|
21412
|
-
|
|
21277
|
+
{ internalType: "address", name: "account", type: "address" }
|
|
21278
|
+
],
|
|
21279
|
+
name: "getVotes",
|
|
21280
|
+
outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
|
|
21281
|
+
stateMutability: "view",
|
|
21282
|
+
type: "function"
|
|
21283
|
+
}
|
|
21284
|
+
];
|
|
21285
|
+
var mainAbi = [
|
|
21286
|
+
{
|
|
21287
|
+
inputs: [],
|
|
21288
|
+
name: "rToken",
|
|
21289
|
+
outputs: [{ internalType: "contract IRToken", name: "", type: "address" }],
|
|
21290
|
+
stateMutability: "view",
|
|
21291
|
+
type: "function"
|
|
21292
|
+
},
|
|
21293
|
+
{
|
|
21294
|
+
inputs: [],
|
|
21295
|
+
name: "stRSR",
|
|
21296
|
+
outputs: [{ internalType: "contract IStRSR", name: "", type: "address" }],
|
|
21297
|
+
stateMutability: "view",
|
|
21298
|
+
type: "function"
|
|
21299
|
+
},
|
|
21300
|
+
{
|
|
21301
|
+
inputs: [],
|
|
21302
|
+
name: "assetRegistry",
|
|
21303
|
+
outputs: [{ internalType: "contract IAssetRegistry", name: "", type: "address" }],
|
|
21304
|
+
stateMutability: "view",
|
|
21305
|
+
type: "function"
|
|
21306
|
+
},
|
|
21307
|
+
{
|
|
21308
|
+
inputs: [],
|
|
21309
|
+
name: "basketHandler",
|
|
21310
|
+
outputs: [{ internalType: "contract IBasketHandler", name: "", type: "address" }],
|
|
21311
|
+
stateMutability: "view",
|
|
21312
|
+
type: "function"
|
|
21313
|
+
},
|
|
21314
|
+
{
|
|
21315
|
+
inputs: [],
|
|
21316
|
+
name: "backingManager",
|
|
21317
|
+
outputs: [{ internalType: "contract IBackingManager", name: "", type: "address" }],
|
|
21318
|
+
stateMutability: "view",
|
|
21319
|
+
type: "function"
|
|
21320
|
+
},
|
|
21321
|
+
{
|
|
21322
|
+
inputs: [],
|
|
21323
|
+
name: "distributor",
|
|
21324
|
+
outputs: [{ internalType: "contract IDistributor", name: "", type: "address" }],
|
|
21325
|
+
stateMutability: "view",
|
|
21326
|
+
type: "function"
|
|
21327
|
+
},
|
|
21328
|
+
{
|
|
21329
|
+
inputs: [],
|
|
21330
|
+
name: "furnace",
|
|
21331
|
+
outputs: [{ internalType: "contract IFurnace", name: "", type: "address" }],
|
|
21332
|
+
stateMutability: "view",
|
|
21333
|
+
type: "function"
|
|
21334
|
+
},
|
|
21335
|
+
{
|
|
21336
|
+
inputs: [],
|
|
21337
|
+
name: "broker",
|
|
21338
|
+
outputs: [{ internalType: "contract IBroker", name: "", type: "address" }],
|
|
21339
|
+
stateMutability: "view",
|
|
21340
|
+
type: "function"
|
|
21341
|
+
},
|
|
21342
|
+
{
|
|
21343
|
+
inputs: [],
|
|
21344
|
+
name: "rsrTrader",
|
|
21345
|
+
outputs: [{ internalType: "contract IRevenueTrader", name: "", type: "address" }],
|
|
21346
|
+
stateMutability: "view",
|
|
21347
|
+
type: "function"
|
|
21348
|
+
},
|
|
21349
|
+
{
|
|
21350
|
+
inputs: [],
|
|
21351
|
+
name: "rTokenTrader",
|
|
21352
|
+
outputs: [{ internalType: "contract IRevenueTrader", name: "", type: "address" }],
|
|
21353
|
+
stateMutability: "view",
|
|
21354
|
+
type: "function"
|
|
21355
|
+
}
|
|
21356
|
+
];
|
|
21357
|
+
async function detectDtfType(publicClient, address) {
|
|
21358
|
+
try {
|
|
21359
|
+
const mainAddress = await publicClient.readContract({
|
|
21360
|
+
address,
|
|
21361
|
+
abi: stRSRAbi,
|
|
21362
|
+
functionName: "main"
|
|
21363
|
+
});
|
|
21364
|
+
const rTokenAddress = await publicClient.readContract({
|
|
21365
|
+
address: mainAddress,
|
|
21366
|
+
abi: mainAbi,
|
|
21367
|
+
functionName: "rToken"
|
|
21368
|
+
});
|
|
21369
|
+
if (rTokenAddress.toLowerCase() === address.toLowerCase()) {
|
|
21370
|
+
return "yield";
|
|
21371
|
+
}
|
|
21372
|
+
return "index";
|
|
21373
|
+
} catch {
|
|
21374
|
+
return "index";
|
|
21375
|
+
}
|
|
21376
|
+
}
|
|
21377
|
+
async function readYieldDtfComponents(publicClient, rTokenAddress) {
|
|
21378
|
+
const mainAddress = await publicClient.readContract({
|
|
21379
|
+
address: rTokenAddress,
|
|
21380
|
+
abi: stRSRAbi,
|
|
21381
|
+
functionName: "main"
|
|
21382
|
+
});
|
|
21383
|
+
const results = await publicClient.multicall({
|
|
21384
|
+
contracts: [
|
|
21385
|
+
{ address: mainAddress, abi: mainAbi, functionName: "rToken" },
|
|
21386
|
+
{ address: mainAddress, abi: mainAbi, functionName: "stRSR" },
|
|
21387
|
+
{ address: mainAddress, abi: mainAbi, functionName: "assetRegistry" },
|
|
21388
|
+
{ address: mainAddress, abi: mainAbi, functionName: "basketHandler" },
|
|
21389
|
+
{ address: mainAddress, abi: mainAbi, functionName: "backingManager" },
|
|
21390
|
+
{ address: mainAddress, abi: mainAbi, functionName: "distributor" },
|
|
21391
|
+
{ address: mainAddress, abi: mainAbi, functionName: "furnace" },
|
|
21392
|
+
{ address: mainAddress, abi: mainAbi, functionName: "broker" },
|
|
21393
|
+
{ address: mainAddress, abi: mainAbi, functionName: "rsrTrader" },
|
|
21394
|
+
{ address: mainAddress, abi: mainAbi, functionName: "rTokenTrader" }
|
|
21395
|
+
],
|
|
21396
|
+
allowFailure: false
|
|
21397
|
+
});
|
|
21398
|
+
return {
|
|
21399
|
+
main: mainAddress,
|
|
21400
|
+
rToken: results[0],
|
|
21401
|
+
stRSR: results[1],
|
|
21402
|
+
assetRegistry: results[2],
|
|
21403
|
+
basketHandler: results[3],
|
|
21404
|
+
backingManager: results[4],
|
|
21405
|
+
distributor: results[5],
|
|
21406
|
+
furnace: results[6],
|
|
21407
|
+
broker: results[7],
|
|
21408
|
+
rsrTrader: results[8],
|
|
21409
|
+
rTokenTrader: results[9]
|
|
21410
|
+
};
|
|
21411
|
+
}
|
|
21412
|
+
var facadeReadAbi = [
|
|
21413
|
+
{
|
|
21414
|
+
inputs: [
|
|
21415
|
+
{ internalType: "contract IRToken", name: "rToken", type: "address" }
|
|
21416
|
+
],
|
|
21417
|
+
name: "backingOverview",
|
|
21418
|
+
outputs: [
|
|
21419
|
+
{ internalType: "uint192", name: "backing", type: "uint192" },
|
|
21420
|
+
{ internalType: "uint192", name: "overCollateralization", type: "uint192" }
|
|
21421
|
+
],
|
|
21422
|
+
stateMutability: "view",
|
|
21423
|
+
type: "function"
|
|
21424
|
+
},
|
|
21425
|
+
{
|
|
21426
|
+
inputs: [
|
|
21427
|
+
{ internalType: "contract IRToken", name: "rToken", type: "address" }
|
|
21428
|
+
],
|
|
21429
|
+
name: "basketBreakdown",
|
|
21430
|
+
outputs: [
|
|
21431
|
+
{ internalType: "address[]", name: "erc20s", type: "address[]" },
|
|
21432
|
+
{ internalType: "uint192[]", name: "uoaShares", type: "uint192[]" },
|
|
21433
|
+
{ internalType: "bytes32[]", name: "targets", type: "bytes32[]" }
|
|
21434
|
+
],
|
|
21435
|
+
stateMutability: "nonpayable",
|
|
21436
|
+
type: "function"
|
|
21437
|
+
},
|
|
21438
|
+
{
|
|
21439
|
+
inputs: [
|
|
21440
|
+
{ internalType: "contract IRToken", name: "rToken", type: "address" }
|
|
21441
|
+
],
|
|
21442
|
+
name: "basketTokens",
|
|
21443
|
+
outputs: [
|
|
21444
|
+
{ internalType: "address[]", name: "tokens", type: "address[]" }
|
|
21445
|
+
],
|
|
21446
|
+
stateMutability: "view",
|
|
21447
|
+
type: "function"
|
|
21448
|
+
},
|
|
21449
|
+
{
|
|
21450
|
+
inputs: [
|
|
21451
|
+
{ internalType: "contract IRToken", name: "rToken", type: "address" },
|
|
21452
|
+
{ internalType: "uint256", name: "amount", type: "uint256" }
|
|
21453
|
+
],
|
|
21454
|
+
name: "issue",
|
|
21455
|
+
outputs: [
|
|
21456
|
+
{ internalType: "address[]", name: "tokens", type: "address[]" },
|
|
21457
|
+
{ internalType: "uint256[]", name: "deposits", type: "uint256[]" },
|
|
21458
|
+
{ internalType: "uint192[]", name: "depositsUoA", type: "uint192[]" }
|
|
21459
|
+
],
|
|
21460
|
+
stateMutability: "nonpayable",
|
|
21461
|
+
type: "function"
|
|
21462
|
+
},
|
|
21463
|
+
{
|
|
21464
|
+
inputs: [
|
|
21465
|
+
{ internalType: "contract IRToken", name: "rToken", type: "address" }
|
|
21466
|
+
],
|
|
21467
|
+
name: "price",
|
|
21468
|
+
outputs: [
|
|
21469
|
+
{ internalType: "uint192", name: "low", type: "uint192" },
|
|
21470
|
+
{ internalType: "uint192", name: "high", type: "uint192" }
|
|
21471
|
+
],
|
|
21472
|
+
stateMutability: "view",
|
|
21473
|
+
type: "function"
|
|
21474
|
+
},
|
|
21475
|
+
{
|
|
21476
|
+
inputs: [
|
|
21477
|
+
{ internalType: "contract IRToken", name: "rToken", type: "address" },
|
|
21478
|
+
{ internalType: "uint256", name: "amount", type: "uint256" }
|
|
21479
|
+
],
|
|
21480
|
+
name: "redeem",
|
|
21481
|
+
outputs: [
|
|
21482
|
+
{ internalType: "address[]", name: "tokens", type: "address[]" },
|
|
21483
|
+
{ internalType: "uint256[]", name: "withdrawals", type: "uint256[]" },
|
|
21484
|
+
{ internalType: "uint256[]", name: "available", type: "uint256[]" }
|
|
21485
|
+
],
|
|
21486
|
+
stateMutability: "nonpayable",
|
|
21487
|
+
type: "function"
|
|
21488
|
+
},
|
|
21489
|
+
{
|
|
21490
|
+
inputs: [
|
|
21491
|
+
{ internalType: "contract IRToken", name: "rToken", type: "address" }
|
|
21492
|
+
],
|
|
21493
|
+
name: "stToken",
|
|
21494
|
+
outputs: [
|
|
21495
|
+
{ internalType: "contract IStRSR", name: "stTokenAddress", type: "address" }
|
|
21496
|
+
],
|
|
21497
|
+
stateMutability: "view",
|
|
21498
|
+
type: "function"
|
|
21499
|
+
}
|
|
21500
|
+
];
|
|
21501
|
+
async function readYieldDtfBasket(publicClient, facadeAddress, rTokenAddress) {
|
|
21502
|
+
const result = await publicClient.readContract({
|
|
21503
|
+
address: facadeAddress,
|
|
21504
|
+
abi: facadeReadAbi,
|
|
21505
|
+
functionName: "basketBreakdown",
|
|
21506
|
+
args: [rTokenAddress]
|
|
21507
|
+
});
|
|
21508
|
+
const [erc20s, uoaShares, targets] = result;
|
|
21509
|
+
const tokenMeta = await fetchTokenMetadata(publicClient, erc20s);
|
|
21510
|
+
return tokenMeta.map((token, i) => ({
|
|
21511
|
+
address: token.address,
|
|
21512
|
+
symbol: token.symbol,
|
|
21513
|
+
decimals: token.decimals,
|
|
21514
|
+
targetUnit: decodeBytes32(targets[i]),
|
|
21515
|
+
uoaShare: uoaShares[i]
|
|
21516
|
+
}));
|
|
21517
|
+
}
|
|
21518
|
+
function decodeBytes32(hex) {
|
|
21519
|
+
if (hex === "0x0000000000000000000000000000000000000000000000000000000000000000")
|
|
21520
|
+
return "";
|
|
21521
|
+
try {
|
|
21522
|
+
return hexToString(hex, { size: 32 });
|
|
21523
|
+
} catch {
|
|
21524
|
+
return hex;
|
|
21525
|
+
}
|
|
21526
|
+
}
|
|
21527
|
+
async function readBackingOverview(publicClient, facadeAddress, rTokenAddress) {
|
|
21528
|
+
const [backing, overCollateralization] = await publicClient.readContract({
|
|
21529
|
+
address: facadeAddress,
|
|
21530
|
+
abi: facadeReadAbi,
|
|
21531
|
+
functionName: "backingOverview",
|
|
21532
|
+
args: [rTokenAddress]
|
|
21533
|
+
});
|
|
21534
|
+
return {
|
|
21535
|
+
backing,
|
|
21536
|
+
overCollateralization
|
|
21537
|
+
};
|
|
21538
|
+
}
|
|
21539
|
+
async function readYieldDtfPrice(publicClient, facadeAddress, rTokenAddress) {
|
|
21540
|
+
const [low, high] = await publicClient.readContract({
|
|
21541
|
+
address: facadeAddress,
|
|
21542
|
+
abi: facadeReadAbi,
|
|
21543
|
+
functionName: "price",
|
|
21544
|
+
args: [rTokenAddress]
|
|
21545
|
+
});
|
|
21546
|
+
return { low, high };
|
|
21547
|
+
}
|
|
21548
|
+
async function readStRSRInfo(publicClient, stRSRAddress, account) {
|
|
21549
|
+
const baseContracts = [
|
|
21550
|
+
{ address: stRSRAddress, abi: stRSRAbi, functionName: "exchangeRate" },
|
|
21551
|
+
{ address: stRSRAddress, abi: stRSRAbi, functionName: "totalSupply" },
|
|
21552
|
+
{ address: stRSRAddress, abi: stRSRAbi, functionName: "unstakingDelay" }
|
|
21553
|
+
];
|
|
21554
|
+
const accountContracts = account ? [
|
|
21555
|
+
{ address: stRSRAddress, abi: stRSRAbi, functionName: "balanceOf", args: [account] },
|
|
21556
|
+
{ address: stRSRAddress, abi: stRSRAbi, functionName: "getVotes", args: [account] },
|
|
21557
|
+
{ address: stRSRAddress, abi: stRSRAbi, functionName: "delegates", args: [account] }
|
|
21558
|
+
] : [];
|
|
21559
|
+
const results = await publicClient.multicall({
|
|
21560
|
+
contracts: [...baseContracts, ...accountContracts],
|
|
21561
|
+
allowFailure: false
|
|
21562
|
+
});
|
|
21563
|
+
const info = {
|
|
21564
|
+
exchangeRate: results[0],
|
|
21565
|
+
totalSupply: results[1],
|
|
21566
|
+
unstakingDelay: results[2]
|
|
21567
|
+
};
|
|
21568
|
+
if (account) {
|
|
21569
|
+
info.balance = results[3];
|
|
21570
|
+
info.votingPower = results[4];
|
|
21571
|
+
info.delegatee = results[5];
|
|
21572
|
+
}
|
|
21573
|
+
return info;
|
|
21574
|
+
}
|
|
21575
|
+
var distributorAbi = [
|
|
21576
|
+
{
|
|
21577
|
+
inputs: [],
|
|
21578
|
+
name: "totals",
|
|
21579
|
+
outputs: [
|
|
21580
|
+
{
|
|
21581
|
+
components: [
|
|
21582
|
+
{ internalType: "uint24", name: "rTokenTotal", type: "uint24" },
|
|
21583
|
+
{ internalType: "uint24", name: "rsrTotal", type: "uint24" }
|
|
21584
|
+
],
|
|
21585
|
+
internalType: "struct RevenueTotals",
|
|
21586
|
+
name: "revTotals",
|
|
21587
|
+
type: "tuple"
|
|
21588
|
+
}
|
|
21589
|
+
],
|
|
21590
|
+
stateMutability: "view",
|
|
21591
|
+
type: "function"
|
|
21592
|
+
}
|
|
21593
|
+
];
|
|
21594
|
+
async function readDistribution(publicClient, distributorAddress) {
|
|
21595
|
+
const result = await publicClient.readContract({
|
|
21596
|
+
address: distributorAddress,
|
|
21597
|
+
abi: distributorAbi,
|
|
21598
|
+
functionName: "totals"
|
|
21599
|
+
});
|
|
21600
|
+
const totals = result;
|
|
21601
|
+
return {
|
|
21602
|
+
rTokenTotal: BigInt(totals.rTokenTotal),
|
|
21603
|
+
rsrTotal: BigInt(totals.rsrTotal)
|
|
21604
|
+
};
|
|
21605
|
+
}
|
|
21606
|
+
async function fetchYieldDtfConfig(publicClient, chainId, rTokenAddress) {
|
|
21607
|
+
const facadeAddress = FACADE_READ_ADDRESS[chainId];
|
|
21608
|
+
if (!facadeAddress) {
|
|
21609
|
+
throw new Error(`No FacadeRead address for chainId ${chainId}`);
|
|
21610
|
+
}
|
|
21611
|
+
const components = await readYieldDtfComponents(publicClient, rTokenAddress);
|
|
21612
|
+
const [basket, backing, price, nameResult, symbolResult, stRSRInfo, distribution] = await Promise.all([
|
|
21613
|
+
readYieldDtfBasket(publicClient, facadeAddress, rTokenAddress),
|
|
21614
|
+
readBackingOverview(publicClient, facadeAddress, rTokenAddress),
|
|
21615
|
+
readYieldDtfPrice(publicClient, facadeAddress, rTokenAddress),
|
|
21616
|
+
publicClient.readContract({
|
|
21617
|
+
address: rTokenAddress,
|
|
21618
|
+
abi: ERC20_META_ABI,
|
|
21619
|
+
functionName: "name"
|
|
21620
|
+
}),
|
|
21621
|
+
publicClient.readContract({
|
|
21622
|
+
address: rTokenAddress,
|
|
21623
|
+
abi: ERC20_META_ABI,
|
|
21624
|
+
functionName: "symbol"
|
|
21625
|
+
}),
|
|
21626
|
+
readStRSRInfo(publicClient, components.stRSR),
|
|
21627
|
+
readDistribution(publicClient, components.distributor)
|
|
21628
|
+
]);
|
|
21629
|
+
return {
|
|
21630
|
+
type: "yield",
|
|
21631
|
+
components,
|
|
21632
|
+
name: nameResult,
|
|
21633
|
+
symbol: symbolResult,
|
|
21634
|
+
basket,
|
|
21635
|
+
backing,
|
|
21636
|
+
priceLow: price.low,
|
|
21637
|
+
priceHigh: price.high,
|
|
21638
|
+
exchangeRate: stRSRInfo.exchangeRate,
|
|
21639
|
+
unstakingDelay: stRSRInfo.unstakingDelay,
|
|
21640
|
+
rTokenTotal: distribution.rTokenTotal,
|
|
21641
|
+
rsrTotal: distribution.rsrTotal
|
|
21642
|
+
};
|
|
21643
|
+
}
|
|
21644
|
+
async function readIssueQuote(publicClient, facadeAddress, rTokenAddress, amount) {
|
|
21645
|
+
const result = await publicClient.readContract({
|
|
21646
|
+
address: facadeAddress,
|
|
21647
|
+
abi: facadeReadAbi,
|
|
21648
|
+
functionName: "issue",
|
|
21649
|
+
args: [rTokenAddress, amount]
|
|
21650
|
+
});
|
|
21651
|
+
const [tokens, deposits, depositsUoA] = result;
|
|
21652
|
+
return { tokens, deposits, depositsUoA };
|
|
21653
|
+
}
|
|
21654
|
+
async function readRedeemQuote(publicClient, facadeAddress, rTokenAddress, amount) {
|
|
21655
|
+
const result = await publicClient.readContract({
|
|
21656
|
+
address: facadeAddress,
|
|
21657
|
+
abi: facadeReadAbi,
|
|
21658
|
+
functionName: "redeem",
|
|
21659
|
+
args: [rTokenAddress, amount]
|
|
21660
|
+
});
|
|
21661
|
+
const [tokens, withdrawals, available] = result;
|
|
21662
|
+
return { tokens, withdrawals, available };
|
|
21663
|
+
}
|
|
21664
|
+
async function readMintQuote(publicClient, folioAddress, shares) {
|
|
21665
|
+
const results = await publicClient.multicall({
|
|
21666
|
+
contracts: [
|
|
21667
|
+
{
|
|
21668
|
+
address: folioAddress,
|
|
21669
|
+
abi: folio_default,
|
|
21670
|
+
functionName: "toAssets",
|
|
21671
|
+
args: [shares, 1]
|
|
21672
|
+
},
|
|
21673
|
+
{
|
|
21674
|
+
address: folioAddress,
|
|
21675
|
+
abi: folio_default,
|
|
21676
|
+
functionName: "mintFee"
|
|
21677
|
+
}
|
|
21678
|
+
]
|
|
21679
|
+
});
|
|
21680
|
+
if (results[0].status !== "success")
|
|
21681
|
+
throw new Error(`toAssets failed for ${folioAddress} with ${shares} shares`);
|
|
21682
|
+
if (results[1].status !== "success")
|
|
21683
|
+
throw new Error(`mintFee failed for ${folioAddress}`);
|
|
21684
|
+
const [assets, amounts] = results[0].result;
|
|
21685
|
+
const mintFee = results[1].result;
|
|
21686
|
+
const minSharesOut = shares - shares * mintFee / D18;
|
|
21687
|
+
return { shares, assets, amounts, mintFee, minSharesOut };
|
|
21688
|
+
}
|
|
21689
|
+
async function readMintFee(publicClient, folioAddress) {
|
|
21690
|
+
return await publicClient.readContract({
|
|
21691
|
+
address: folioAddress,
|
|
21692
|
+
abi: folio_default,
|
|
21693
|
+
functionName: "mintFee"
|
|
21694
|
+
});
|
|
21695
|
+
}
|
|
21696
|
+
function applySlippage(amount, slippageBps) {
|
|
21697
|
+
if (slippageBps < 0n || slippageBps > 10000n) {
|
|
21698
|
+
throw new Error(`slippageBps must be between 0 and 10000, got ${slippageBps}`);
|
|
21699
|
+
}
|
|
21700
|
+
return amount - amount * slippageBps / 10000n;
|
|
21701
|
+
}
|
|
21702
|
+
async function readRedeemQuote2(publicClient, folioAddress, shares) {
|
|
21703
|
+
const result = await publicClient.readContract({
|
|
21704
|
+
address: folioAddress,
|
|
21705
|
+
abi: folio_default,
|
|
21706
|
+
functionName: "toAssets",
|
|
21707
|
+
args: [shares, 0]
|
|
21708
|
+
});
|
|
21709
|
+
const [assets, amounts] = result;
|
|
21710
|
+
return { shares, assets, amounts };
|
|
21711
|
+
}
|
|
21712
|
+
async function readPendingFees(publicClient, folioAddress) {
|
|
21713
|
+
const results = await publicClient.multicall({
|
|
21714
|
+
contracts: [
|
|
21715
|
+
{
|
|
21716
|
+
address: folioAddress,
|
|
21717
|
+
abi: folio_default,
|
|
21718
|
+
functionName: "getPendingFeeShares"
|
|
21719
|
+
},
|
|
21720
|
+
{
|
|
21721
|
+
address: folioAddress,
|
|
21722
|
+
abi: folio_default,
|
|
21723
|
+
functionName: "feeRecipientsPendingFeeShares"
|
|
21724
|
+
},
|
|
21725
|
+
{
|
|
21726
|
+
address: folioAddress,
|
|
21727
|
+
abi: folio_default,
|
|
21728
|
+
functionName: "daoPendingFeeShares"
|
|
21729
|
+
}
|
|
21730
|
+
]
|
|
21731
|
+
});
|
|
21732
|
+
const total = results[0].status === "success" ? results[0].result : 0n;
|
|
21733
|
+
const folio = results[1].status === "success" ? results[1].result : 0n;
|
|
21734
|
+
const dao = results[2].status === "success" ? results[2].result : 0n;
|
|
21735
|
+
return { total, folio, dao };
|
|
21736
|
+
}
|
|
21737
|
+
async function readFeeRecipients(publicClient, folioAddress) {
|
|
21738
|
+
const indices = Array.from({ length: 10 }, (_, i) => i);
|
|
21739
|
+
const results = await publicClient.multicall({
|
|
21740
|
+
contracts: indices.map((i) => ({
|
|
21741
|
+
address: folioAddress,
|
|
21742
|
+
abi: folio_default,
|
|
21743
|
+
functionName: "feeRecipients",
|
|
21744
|
+
args: [BigInt(i)]
|
|
21745
|
+
}))
|
|
21746
|
+
});
|
|
21747
|
+
const recipients = [];
|
|
21748
|
+
for (const r of results) {
|
|
21749
|
+
if (r.status !== "success")
|
|
21750
|
+
break;
|
|
21751
|
+
const [recipient, portion] = r.result;
|
|
21752
|
+
recipients.push({ recipient, portion });
|
|
21753
|
+
}
|
|
21754
|
+
return recipients;
|
|
21755
|
+
}
|
|
21756
|
+
async function fetchRebalanceHistory(chainId, folioAddress, opts, baseUrl = RESERVE_API_BASE_URL) {
|
|
21757
|
+
const skip = opts?.skip ?? 0;
|
|
21758
|
+
const limit = opts?.limit ?? 50;
|
|
21759
|
+
const url = `${baseUrl}/dtf/rebalance?address=${folioAddress.toLowerCase()}&chainId=${chainId}&skip=${skip}&limit=${limit}`;
|
|
21760
|
+
const response = await fetchWithRetry(url);
|
|
21761
|
+
if (!response.ok) {
|
|
21762
|
+
throw new Error(`Reserve API /dtf/rebalance failed: ${response.status} ${response.statusText}`);
|
|
21763
|
+
}
|
|
21764
|
+
return await response.json();
|
|
21765
|
+
}
|
|
21766
|
+
async function fetchRebalanceDetail(chainId, folioAddress, nonce, baseUrl = RESERVE_API_BASE_URL) {
|
|
21767
|
+
const url = `${baseUrl}/dtf/rebalance?address=${folioAddress.toLowerCase()}&chainId=${chainId}&nonce=${nonce}`;
|
|
21768
|
+
const response = await fetchWithRetry(url);
|
|
21769
|
+
if (!response.ok) {
|
|
21770
|
+
throw new Error(`Reserve API /dtf/rebalance detail failed: ${response.status} ${response.statusText}`);
|
|
21771
|
+
}
|
|
21772
|
+
return await response.json();
|
|
21773
|
+
}
|
|
21774
|
+
async function fetchHistoricalDtf(chainId, folioAddress, opts, baseUrl = RESERVE_API_BASE_URL) {
|
|
21775
|
+
const now = Math.floor(Date.now() / 1000);
|
|
21776
|
+
const to = opts?.to ?? now;
|
|
21777
|
+
const from14 = opts?.from ?? to - 2592000;
|
|
21778
|
+
const interval = opts?.interval ?? "1h";
|
|
21779
|
+
const url = `${baseUrl}/historical/dtf?address=${folioAddress.toLowerCase()}&chainId=${chainId}&from=${from14}&to=${to}&interval=${interval}`;
|
|
21780
|
+
const response = await fetchWithRetry(url);
|
|
21781
|
+
if (!response.ok) {
|
|
21782
|
+
throw new Error(`Reserve API /historical/dtf failed: ${response.status} ${response.statusText}`);
|
|
21783
|
+
}
|
|
21784
|
+
const data = await response.json();
|
|
21785
|
+
if (Array.isArray(data))
|
|
21786
|
+
return data;
|
|
21787
|
+
return data.timeseries ?? [];
|
|
21788
|
+
}
|
|
21789
|
+
async function fetchHistoricalPrices(chainId, tokenAddress, opts, baseUrl = RESERVE_API_BASE_URL) {
|
|
21790
|
+
const now = Math.floor(Date.now() / 1000);
|
|
21791
|
+
const to = opts?.to ?? now;
|
|
21792
|
+
const from14 = opts?.from ?? to - 2592000;
|
|
21793
|
+
const interval = opts?.interval ?? "1h";
|
|
21794
|
+
const url = `${baseUrl}/historical/prices?address=${tokenAddress.toLowerCase()}&chainId=${chainId}&from=${from14}&to=${to}&interval=${interval}`;
|
|
21795
|
+
const response = await fetchWithRetry(url);
|
|
21796
|
+
if (!response.ok) {
|
|
21797
|
+
throw new Error(`Reserve API /historical/prices failed: ${response.status} ${response.statusText}`);
|
|
21798
|
+
}
|
|
21799
|
+
const data = await response.json();
|
|
21800
|
+
if (Array.isArray(data))
|
|
21801
|
+
return data;
|
|
21802
|
+
return data.timeseries ?? [];
|
|
21803
|
+
}
|
|
21804
|
+
var governor_default = [
|
|
21805
|
+
{
|
|
21806
|
+
type: "constructor",
|
|
21807
|
+
inputs: [],
|
|
21808
|
+
stateMutability: "nonpayable"
|
|
21809
|
+
},
|
|
21810
|
+
{
|
|
21811
|
+
type: "receive",
|
|
21812
|
+
stateMutability: "payable"
|
|
21813
|
+
},
|
|
21814
|
+
{
|
|
21815
|
+
type: "function",
|
|
21816
|
+
name: "BALLOT_TYPEHASH",
|
|
21817
|
+
inputs: [],
|
|
21818
|
+
outputs: [
|
|
21819
|
+
{
|
|
21820
|
+
name: "",
|
|
21821
|
+
type: "bytes32",
|
|
21822
|
+
internalType: "bytes32"
|
|
21823
|
+
}
|
|
21824
|
+
],
|
|
21825
|
+
stateMutability: "view"
|
|
21826
|
+
},
|
|
21827
|
+
{
|
|
21828
|
+
type: "function",
|
|
21829
|
+
name: "CLOCK_MODE",
|
|
21830
|
+
inputs: [],
|
|
21831
|
+
outputs: [
|
|
21832
|
+
{
|
|
21833
|
+
name: "",
|
|
21834
|
+
type: "string",
|
|
21835
|
+
internalType: "string"
|
|
21836
|
+
}
|
|
21837
|
+
],
|
|
21838
|
+
stateMutability: "view"
|
|
21839
|
+
},
|
|
21840
|
+
{
|
|
21841
|
+
type: "function",
|
|
21842
|
+
name: "COUNTING_MODE",
|
|
21843
|
+
inputs: [],
|
|
21844
|
+
outputs: [
|
|
21845
|
+
{
|
|
21846
|
+
name: "",
|
|
21847
|
+
type: "string",
|
|
21848
|
+
internalType: "string"
|
|
21849
|
+
}
|
|
21850
|
+
],
|
|
21851
|
+
stateMutability: "pure"
|
|
21852
|
+
},
|
|
21853
|
+
{
|
|
21854
|
+
type: "function",
|
|
21855
|
+
name: "EXTENDED_BALLOT_TYPEHASH",
|
|
21856
|
+
inputs: [],
|
|
21857
|
+
outputs: [
|
|
21858
|
+
{
|
|
21859
|
+
name: "",
|
|
21860
|
+
type: "bytes32",
|
|
21861
|
+
internalType: "bytes32"
|
|
21862
|
+
}
|
|
21863
|
+
],
|
|
21864
|
+
stateMutability: "view"
|
|
21865
|
+
},
|
|
21866
|
+
{
|
|
21867
|
+
type: "function",
|
|
21868
|
+
name: "cancel",
|
|
21869
|
+
inputs: [
|
|
21870
|
+
{
|
|
21871
|
+
name: "targets",
|
|
21872
|
+
type: "address[]",
|
|
21873
|
+
internalType: "address[]"
|
|
21874
|
+
},
|
|
21875
|
+
{
|
|
21876
|
+
name: "values",
|
|
21877
|
+
type: "uint256[]",
|
|
21878
|
+
internalType: "uint256[]"
|
|
21879
|
+
},
|
|
21880
|
+
{
|
|
21881
|
+
name: "calldatas",
|
|
21882
|
+
type: "bytes[]",
|
|
21883
|
+
internalType: "bytes[]"
|
|
21884
|
+
},
|
|
21885
|
+
{
|
|
21886
|
+
name: "descriptionHash",
|
|
21887
|
+
type: "bytes32",
|
|
21888
|
+
internalType: "bytes32"
|
|
21889
|
+
}
|
|
21890
|
+
],
|
|
21891
|
+
outputs: [
|
|
21892
|
+
{
|
|
21893
|
+
name: "",
|
|
21894
|
+
type: "uint256",
|
|
21895
|
+
internalType: "uint256"
|
|
21896
|
+
}
|
|
21897
|
+
],
|
|
21898
|
+
stateMutability: "nonpayable"
|
|
21899
|
+
},
|
|
21900
|
+
{
|
|
21901
|
+
type: "function",
|
|
21902
|
+
name: "castVote",
|
|
21903
|
+
inputs: [
|
|
21904
|
+
{
|
|
21905
|
+
name: "proposalId",
|
|
21906
|
+
type: "uint256",
|
|
21907
|
+
internalType: "uint256"
|
|
21908
|
+
},
|
|
21909
|
+
{
|
|
21910
|
+
name: "support",
|
|
21911
|
+
type: "uint8",
|
|
21912
|
+
internalType: "uint8"
|
|
21413
21913
|
}
|
|
21414
21914
|
],
|
|
21415
21915
|
outputs: [
|
|
@@ -25137,6 +25637,7 @@ function computeHistoricalBurnTotals(burns, prices) {
|
|
|
25137
25637
|
|
|
25138
25638
|
// src/lib/cached-config.ts
|
|
25139
25639
|
var CACHE_NAMESPACE = "config";
|
|
25640
|
+
var YIELD_CACHE_NAMESPACE = "yield-config";
|
|
25140
25641
|
async function fetchDtfConfigCached(fetchFn, publicClient, chainId, address) {
|
|
25141
25642
|
const cacheKey3 = `${CACHE_NAMESPACE}:${address.toLowerCase()}`;
|
|
25142
25643
|
const cached = getCached(chainId, cacheKey3);
|
|
@@ -25146,6 +25647,22 @@ async function fetchDtfConfigCached(fetchFn, publicClient, chainId, address) {
|
|
|
25146
25647
|
setCache(chainId, cacheKey3, config);
|
|
25147
25648
|
return config;
|
|
25148
25649
|
}
|
|
25650
|
+
async function fetchYieldDtfConfigCached(fetchFn, publicClient, chainId, address) {
|
|
25651
|
+
const cacheKey3 = `${YIELD_CACHE_NAMESPACE}:${address.toLowerCase()}`;
|
|
25652
|
+
const cached = getCached(chainId, cacheKey3);
|
|
25653
|
+
if (cached)
|
|
25654
|
+
return cached;
|
|
25655
|
+
const config = await fetchFn(publicClient, chainId, address);
|
|
25656
|
+
setCache(chainId, cacheKey3, config);
|
|
25657
|
+
return config;
|
|
25658
|
+
}
|
|
25659
|
+
|
|
25660
|
+
// src/lib/detect-type.ts
|
|
25661
|
+
async function resolveDtfType(publicClient, address, registryType) {
|
|
25662
|
+
if (registryType)
|
|
25663
|
+
return registryType;
|
|
25664
|
+
return detectDtfType(publicClient, address);
|
|
25665
|
+
}
|
|
25149
25666
|
|
|
25150
25667
|
// src/lib/output.ts
|
|
25151
25668
|
function printTable(columns, rows) {
|
|
@@ -25231,10 +25748,16 @@ async function infoCommand(address, config) {
|
|
|
25231
25748
|
chainId: config.chainId,
|
|
25232
25749
|
rpc: config.rpc
|
|
25233
25750
|
});
|
|
25751
|
+
const dtfType = await resolveDtfType(publicClient, address, config.dtfType);
|
|
25752
|
+
if (dtfType === "yield") {
|
|
25753
|
+
await yieldInfo(publicClient, address, config);
|
|
25754
|
+
return;
|
|
25755
|
+
}
|
|
25234
25756
|
const dtfConfig = await fetchDtfConfigCached(fetchDtfConfig, publicClient, config.chainId, address);
|
|
25235
25757
|
if (config.json) {
|
|
25236
25758
|
printJson({
|
|
25237
25759
|
dtf: address,
|
|
25760
|
+
type: "index",
|
|
25238
25761
|
chain: config.chainId,
|
|
25239
25762
|
chainLabel: chainLabel(config.chainId),
|
|
25240
25763
|
ownerGovernance: govToJson(dtfConfig.ownerGovernance),
|
|
@@ -25261,6 +25784,7 @@ async function infoCommand(address, config) {
|
|
|
25261
25784
|
console.log();
|
|
25262
25785
|
const rows = [
|
|
25263
25786
|
{ prop: "DTF Address", value: address },
|
|
25787
|
+
{ prop: "Type", value: "Index DTF" },
|
|
25264
25788
|
{ prop: "Auction Length", value: formatDuration(dtfConfig.auctionLength) }
|
|
25265
25789
|
];
|
|
25266
25790
|
if (dtfConfig.mandate) {
|
|
@@ -25322,11 +25846,99 @@ async function infoCommand(address, config) {
|
|
|
25322
25846
|
], roleRows);
|
|
25323
25847
|
}
|
|
25324
25848
|
}
|
|
25849
|
+
async function yieldInfo(publicClient, address, config) {
|
|
25850
|
+
const yieldConfig = await fetchYieldDtfConfigCached(fetchYieldDtfConfig, publicClient, config.chainId, address);
|
|
25851
|
+
const backingPct = Number(yieldConfig.backing.backing) / Number(D18);
|
|
25852
|
+
const overCollPct = Number(yieldConfig.backing.overCollateralization) / Number(D18);
|
|
25853
|
+
const priceLow = Number(yieldConfig.priceLow) / Number(D18);
|
|
25854
|
+
const priceHigh = Number(yieldConfig.priceHigh) / Number(D18);
|
|
25855
|
+
const exchangeRate = Number(yieldConfig.exchangeRate) / Number(D18);
|
|
25856
|
+
const totalDist = Number(yieldConfig.rTokenTotal) + Number(yieldConfig.rsrTotal);
|
|
25857
|
+
const rTokenPct = totalDist > 0 ? Number(yieldConfig.rTokenTotal) / totalDist : 0;
|
|
25858
|
+
const rsrPct = totalDist > 0 ? 1 - rTokenPct : 0;
|
|
25859
|
+
if (config.json) {
|
|
25860
|
+
printJson({
|
|
25861
|
+
dtf: address,
|
|
25862
|
+
type: "yield",
|
|
25863
|
+
chain: config.chainId,
|
|
25864
|
+
chainLabel: chainLabel(config.chainId),
|
|
25865
|
+
name: yieldConfig.name,
|
|
25866
|
+
symbol: yieldConfig.symbol,
|
|
25867
|
+
components: yieldConfig.components,
|
|
25868
|
+
backing: yieldConfig.backing.backing.toString(),
|
|
25869
|
+
backingPercent: backingPct * 100,
|
|
25870
|
+
overCollateralization: yieldConfig.backing.overCollateralization.toString(),
|
|
25871
|
+
overCollateralizationPercent: overCollPct * 100,
|
|
25872
|
+
priceLow: yieldConfig.priceLow.toString(),
|
|
25873
|
+
priceHigh: yieldConfig.priceHigh.toString(),
|
|
25874
|
+
priceLowHuman: priceLow,
|
|
25875
|
+
priceHighHuman: priceHigh,
|
|
25876
|
+
exchangeRate: yieldConfig.exchangeRate.toString(),
|
|
25877
|
+
exchangeRateHuman: exchangeRate,
|
|
25878
|
+
unstakingDelay: yieldConfig.unstakingDelay.toString(),
|
|
25879
|
+
unstakingDelayHuman: formatDuration(Number(yieldConfig.unstakingDelay)),
|
|
25880
|
+
rTokenTotal: yieldConfig.rTokenTotal.toString(),
|
|
25881
|
+
rsrTotal: yieldConfig.rsrTotal.toString(),
|
|
25882
|
+
distributionPercent: { holders: rTokenPct * 100, stakers: rsrPct * 100 },
|
|
25883
|
+
basket: yieldConfig.basket.map((t) => ({
|
|
25884
|
+
address: t.address,
|
|
25885
|
+
symbol: t.symbol,
|
|
25886
|
+
decimals: t.decimals,
|
|
25887
|
+
targetUnit: t.targetUnit,
|
|
25888
|
+
uoaShare: t.uoaShare.toString(),
|
|
25889
|
+
uoaSharePercent: Number(t.uoaShare) / Number(D18) * 100
|
|
25890
|
+
}))
|
|
25891
|
+
});
|
|
25892
|
+
return;
|
|
25893
|
+
}
|
|
25894
|
+
printHeader(`Yield DTF Info — ${yieldConfig.symbol} (${chainLabel(config.chainId)})`);
|
|
25895
|
+
console.log();
|
|
25896
|
+
printTable([
|
|
25897
|
+
{ header: "Property", key: "prop" },
|
|
25898
|
+
{ header: "Value", key: "value" }
|
|
25899
|
+
], [
|
|
25900
|
+
{ prop: "Name", value: yieldConfig.name },
|
|
25901
|
+
{ prop: "Symbol", value: yieldConfig.symbol },
|
|
25902
|
+
{ prop: "Type", value: "Yield DTF (RToken)" },
|
|
25903
|
+
{ prop: "Address", value: address },
|
|
25904
|
+
{ prop: "Price", value: `$${priceLow.toFixed(4)} - $${priceHigh.toFixed(4)}` },
|
|
25905
|
+
{ prop: "Backing", value: formatPct(backingPct) },
|
|
25906
|
+
{ prop: "Over-collateralization", value: formatPct(overCollPct) },
|
|
25907
|
+
{ prop: "Revenue Split", value: `${formatPct(rTokenPct)} holders / ${formatPct(rsrPct)} stakers` },
|
|
25908
|
+
{ prop: "StRSR Exchange Rate", value: `${exchangeRate.toFixed(6)} RSR/stRSR` },
|
|
25909
|
+
{ prop: "Unstaking Delay", value: formatDuration(Number(yieldConfig.unstakingDelay)) },
|
|
25910
|
+
{ prop: "Main", value: yieldConfig.components.main },
|
|
25911
|
+
{ prop: "StRSR", value: yieldConfig.components.stRSR }
|
|
25912
|
+
]);
|
|
25913
|
+
if (yieldConfig.basket.length > 0) {
|
|
25914
|
+
console.log();
|
|
25915
|
+
printTable([
|
|
25916
|
+
{ header: "Token", key: "symbol" },
|
|
25917
|
+
{ header: "Target", key: "target" },
|
|
25918
|
+
{ header: "UoA Share", key: "share", align: "right" },
|
|
25919
|
+
{ header: "Address", key: "address" }
|
|
25920
|
+
], yieldConfig.basket.map((t) => ({
|
|
25921
|
+
symbol: t.symbol,
|
|
25922
|
+
target: t.targetUnit,
|
|
25923
|
+
share: formatPct(Number(t.uoaShare) / Number(D18)),
|
|
25924
|
+
address: formatAddress(t.address)
|
|
25925
|
+
})));
|
|
25926
|
+
}
|
|
25927
|
+
}
|
|
25325
25928
|
|
|
25326
25929
|
// ../../node_modules/.bun/viem@2.46.2+1fb4c65d43e298b9/node_modules/viem/_esm/index.js
|
|
25327
25930
|
init_isAddress();
|
|
25328
25931
|
// src/commands/basket.ts
|
|
25329
25932
|
async function basketCommand(address, config) {
|
|
25933
|
+
const { publicClient } = createDtfClients({
|
|
25934
|
+
chainId: config.chainId,
|
|
25935
|
+
rpc: config.rpc
|
|
25936
|
+
});
|
|
25937
|
+
const dtfType = await resolveDtfType(publicClient, address, config.dtfType);
|
|
25938
|
+
if (dtfType === "yield") {
|
|
25939
|
+
await yieldBasket(publicClient, address, config);
|
|
25940
|
+
return;
|
|
25941
|
+
}
|
|
25330
25942
|
try {
|
|
25331
25943
|
await basketFromApi(address, config);
|
|
25332
25944
|
} catch {
|
|
@@ -25334,6 +25946,43 @@ async function basketCommand(address, config) {
|
|
|
25334
25946
|
await basketFromRpc(address, config);
|
|
25335
25947
|
}
|
|
25336
25948
|
}
|
|
25949
|
+
async function yieldBasket(publicClient, address, config) {
|
|
25950
|
+
const facadeAddress = FACADE_READ_ADDRESS[config.chainId];
|
|
25951
|
+
if (!facadeAddress) {
|
|
25952
|
+
throw new Error(`No FacadeRead address for chain ${config.chainId}`);
|
|
25953
|
+
}
|
|
25954
|
+
const basket = await readYieldDtfBasket(publicClient, facadeAddress, address);
|
|
25955
|
+
if (config.json) {
|
|
25956
|
+
printJson({
|
|
25957
|
+
dtf: address,
|
|
25958
|
+
type: "yield",
|
|
25959
|
+
chain: config.chainId,
|
|
25960
|
+
chainLabel: chainLabel(config.chainId),
|
|
25961
|
+
tokens: basket.map((t) => ({
|
|
25962
|
+
address: t.address,
|
|
25963
|
+
symbol: t.symbol,
|
|
25964
|
+
decimals: t.decimals,
|
|
25965
|
+
targetUnit: t.targetUnit,
|
|
25966
|
+
uoaShare: t.uoaShare.toString(),
|
|
25967
|
+
uoaSharePercent: Number(t.uoaShare) / Number(D18) * 100
|
|
25968
|
+
}))
|
|
25969
|
+
});
|
|
25970
|
+
return;
|
|
25971
|
+
}
|
|
25972
|
+
printHeader(`Yield DTF Basket — ${formatAddress(address)} (${chainLabel(config.chainId)})`);
|
|
25973
|
+
console.log();
|
|
25974
|
+
printTable([
|
|
25975
|
+
{ header: "Token", key: "symbol" },
|
|
25976
|
+
{ header: "Target", key: "target" },
|
|
25977
|
+
{ header: "UoA Share", key: "share", align: "right" },
|
|
25978
|
+
{ header: "Address", key: "address" }
|
|
25979
|
+
], basket.map((t) => ({
|
|
25980
|
+
symbol: t.symbol,
|
|
25981
|
+
target: t.targetUnit,
|
|
25982
|
+
share: formatPct(Number(t.uoaShare) / Number(D18)),
|
|
25983
|
+
address: formatAddress(t.address)
|
|
25984
|
+
})));
|
|
25985
|
+
}
|
|
25337
25986
|
async function basketFromApi(address, config) {
|
|
25338
25987
|
const { publicClient } = createDtfClients({
|
|
25339
25988
|
chainId: config.chainId,
|
|
@@ -25350,6 +25999,7 @@ async function basketFromApi(address, config) {
|
|
|
25350
25999
|
if (config.json) {
|
|
25351
26000
|
printJson({
|
|
25352
26001
|
dtf: address,
|
|
26002
|
+
type: "index",
|
|
25353
26003
|
chain: config.chainId,
|
|
25354
26004
|
chainLabel: chainLabel(config.chainId),
|
|
25355
26005
|
tokens: data.basket.map((t) => ({
|
|
@@ -25405,6 +26055,7 @@ async function basketFromRpc(address, config) {
|
|
|
25405
26055
|
if (config.json) {
|
|
25406
26056
|
printJson({
|
|
25407
26057
|
dtf: address,
|
|
26058
|
+
type: "index",
|
|
25408
26059
|
chain: config.chainId,
|
|
25409
26060
|
chainLabel: chainLabel(config.chainId),
|
|
25410
26061
|
tokens: tokenValues.map((t) => ({
|
|
@@ -25728,6 +26379,16 @@ async function rebalanceCommand(address, config) {
|
|
|
25728
26379
|
chainId: config.chainId,
|
|
25729
26380
|
rpc: config.rpc
|
|
25730
26381
|
});
|
|
26382
|
+
const dtfType = await resolveDtfType(publicClient, address, config.dtfType);
|
|
26383
|
+
if (dtfType === "yield") {
|
|
26384
|
+
const msg = "Yield DTFs rebalance automatically via BackingManager. No manual rebalance state.";
|
|
26385
|
+
if (config.json) {
|
|
26386
|
+
printJson({ dtf: address, type: "yield", chain: config.chainId, chainLabel: chainLabel(config.chainId), message: msg });
|
|
26387
|
+
} else {
|
|
26388
|
+
console.log(msg);
|
|
26389
|
+
}
|
|
26390
|
+
return;
|
|
26391
|
+
}
|
|
25731
26392
|
const [rebalance, auction] = await Promise.all([
|
|
25732
26393
|
readRebalanceState(publicClient, address),
|
|
25733
26394
|
readActiveAuction(publicClient, address)
|
|
@@ -25861,6 +26522,21 @@ No active auction.`);
|
|
|
25861
26522
|
}
|
|
25862
26523
|
}
|
|
25863
26524
|
|
|
26525
|
+
// src/lib/periods.ts
|
|
26526
|
+
var PERIOD_SECONDS = {
|
|
26527
|
+
"30d": 30 * 24 * 60 * 60,
|
|
26528
|
+
"3m": 90 * 24 * 60 * 60,
|
|
26529
|
+
"6m": 180 * 24 * 60 * 60,
|
|
26530
|
+
"1y": 365 * 24 * 60 * 60
|
|
26531
|
+
};
|
|
26532
|
+
function parsePeriodSeconds(period) {
|
|
26533
|
+
const s = PERIOD_SECONDS[period];
|
|
26534
|
+
if (!s) {
|
|
26535
|
+
throw new Error(`Unknown period "${period}". Use: 30d, 3m, 6m, 1y`);
|
|
26536
|
+
}
|
|
26537
|
+
return s;
|
|
26538
|
+
}
|
|
26539
|
+
|
|
25864
26540
|
// src/commands/prices.ts
|
|
25865
26541
|
async function pricesCommand(address, config) {
|
|
25866
26542
|
const { publicClient } = createDtfClients({
|
|
@@ -25875,23 +26551,53 @@ async function pricesCommand(address, config) {
|
|
|
25875
26551
|
fetchTokenVolatility(config.chainId),
|
|
25876
26552
|
readChainlinkPrice(priceClient)
|
|
25877
26553
|
]);
|
|
26554
|
+
const perfPeriod = config.performance;
|
|
26555
|
+
let tokenReturns = null;
|
|
26556
|
+
if (perfPeriod) {
|
|
26557
|
+
const now = Math.floor(Date.now() / 1000);
|
|
26558
|
+
const seconds = parsePeriodSeconds(perfPeriod);
|
|
26559
|
+
const histResults = await Promise.allSettled(tokenAddresses.map((addr) => fetchHistoricalPrices(config.chainId, addr, {
|
|
26560
|
+
from: now - seconds,
|
|
26561
|
+
to: now,
|
|
26562
|
+
interval: "1d"
|
|
26563
|
+
})));
|
|
26564
|
+
tokenReturns = new Map;
|
|
26565
|
+
for (let i = 0;i < tokenAddresses.length; i++) {
|
|
26566
|
+
const hist = histResults[i];
|
|
26567
|
+
let ret = null;
|
|
26568
|
+
if (hist?.status === "fulfilled" && hist.value.length >= 2) {
|
|
26569
|
+
const first = hist.value[0];
|
|
26570
|
+
const last = hist.value[hist.value.length - 1];
|
|
26571
|
+
if (first.price > 0) {
|
|
26572
|
+
ret = Math.round((last.price - first.price) / first.price * 1e4) / 100;
|
|
26573
|
+
}
|
|
26574
|
+
}
|
|
26575
|
+
tokenReturns.set(tokenAddresses[i].toLowerCase(), ret);
|
|
26576
|
+
}
|
|
26577
|
+
}
|
|
26578
|
+
let tokens = basket.tokens.map((t) => {
|
|
26579
|
+
const addr = t.address.toLowerCase();
|
|
26580
|
+
const vol = volatility[addr] ?? "high";
|
|
26581
|
+
const ret = tokenReturns?.get(addr) ?? null;
|
|
26582
|
+
return { ...t, addr, vol, price: prices[addr] ?? 0, ret };
|
|
26583
|
+
});
|
|
26584
|
+
if (tokenReturns) {
|
|
26585
|
+
tokens = [...tokens].sort((a, b) => (b.ret ?? -Infinity) - (a.ret ?? -Infinity));
|
|
26586
|
+
}
|
|
25878
26587
|
if (config.json) {
|
|
25879
26588
|
printJson({
|
|
25880
26589
|
dtf: address,
|
|
25881
26590
|
chain: config.chainId,
|
|
25882
26591
|
chainLabel: chainLabel(config.chainId),
|
|
25883
|
-
tokens:
|
|
25884
|
-
|
|
25885
|
-
|
|
25886
|
-
|
|
25887
|
-
|
|
25888
|
-
|
|
25889
|
-
|
|
25890
|
-
|
|
25891
|
-
|
|
25892
|
-
proposalPriceError: proposalVolatilityToPriceError(vol)
|
|
25893
|
-
};
|
|
25894
|
-
}),
|
|
26592
|
+
tokens: tokens.map((t) => ({
|
|
26593
|
+
symbol: t.symbol,
|
|
26594
|
+
address: t.address,
|
|
26595
|
+
price: t.price,
|
|
26596
|
+
volatility: t.vol,
|
|
26597
|
+
auctionPriceError: volatilityToPriceError(t.vol),
|
|
26598
|
+
proposalPriceError: proposalVolatilityToPriceError(t.vol),
|
|
26599
|
+
...tokenReturns ? { [`return_${perfPeriod}`]: t.ret } : {}
|
|
26600
|
+
})),
|
|
25895
26601
|
btcUsd: btcPrice ? {
|
|
25896
26602
|
price: btcPrice.record.priceUsd,
|
|
25897
26603
|
timestamp: btcPrice.record.timestamp,
|
|
@@ -25902,25 +26608,30 @@ async function pricesCommand(address, config) {
|
|
|
25902
26608
|
}
|
|
25903
26609
|
printHeader(`DTF Prices — ${formatAddress(address)} (Chain ${config.chainId})`);
|
|
25904
26610
|
console.log();
|
|
25905
|
-
|
|
26611
|
+
const columns = [
|
|
25906
26612
|
{ header: "Token", key: "symbol" },
|
|
25907
26613
|
{ header: "Address", key: "address" },
|
|
25908
26614
|
{ header: "Price (USD)", key: "price", align: "right" },
|
|
25909
26615
|
{ header: "Volatility", key: "volatility" },
|
|
25910
26616
|
{ header: "Auction Error", key: "auctionErr", align: "right" },
|
|
25911
26617
|
{ header: "Proposal Error", key: "proposalErr", align: "right" }
|
|
25912
|
-
]
|
|
25913
|
-
|
|
25914
|
-
|
|
25915
|
-
|
|
25916
|
-
|
|
26618
|
+
];
|
|
26619
|
+
if (tokenReturns) {
|
|
26620
|
+
columns.push({ header: perfPeriod, key: "retPeriod", align: "right" });
|
|
26621
|
+
}
|
|
26622
|
+
printTable(columns, tokens.map((t) => {
|
|
26623
|
+
const row = {
|
|
25917
26624
|
symbol: t.symbol,
|
|
25918
26625
|
address: formatAddress(t.address),
|
|
25919
|
-
price: formatUsd(price),
|
|
25920
|
-
volatility: vol,
|
|
25921
|
-
auctionErr: `${(volatilityToPriceError(vol) * 100).toFixed(0)}%`,
|
|
25922
|
-
proposalErr: `${(proposalVolatilityToPriceError(vol) * 100).toFixed(0)}%`
|
|
26626
|
+
price: formatUsd(t.price),
|
|
26627
|
+
volatility: t.vol,
|
|
26628
|
+
auctionErr: `${(volatilityToPriceError(t.vol) * 100).toFixed(0)}%`,
|
|
26629
|
+
proposalErr: `${(proposalVolatilityToPriceError(t.vol) * 100).toFixed(0)}%`
|
|
25923
26630
|
};
|
|
26631
|
+
if (tokenReturns) {
|
|
26632
|
+
row.retPeriod = t.ret !== null ? `${t.ret > 0 ? "+" : ""}${t.ret}%` : "—";
|
|
26633
|
+
}
|
|
26634
|
+
return row;
|
|
25924
26635
|
}));
|
|
25925
26636
|
if (btcPrice) {
|
|
25926
26637
|
console.log();
|
|
@@ -25942,6 +26653,11 @@ async function quoteCommand(address, config, rest) {
|
|
|
25942
26653
|
chainId: config.chainId,
|
|
25943
26654
|
rpc: config.rpc
|
|
25944
26655
|
});
|
|
26656
|
+
const dtfType = await resolveDtfType(publicClient, address, config.dtfType);
|
|
26657
|
+
if (dtfType === "yield") {
|
|
26658
|
+
await yieldQuote(publicClient, address, config, shares, action);
|
|
26659
|
+
return;
|
|
26660
|
+
}
|
|
25945
26661
|
const dtfConfig = config.json ? await fetchDtfConfigCached(fetchDtfConfig, publicClient, config.chainId, address) : null;
|
|
25946
26662
|
const tokenByAddress = new Map((dtfConfig?.tokens ?? []).map((t) => [t.address.toLowerCase(), t]));
|
|
25947
26663
|
if (action === "mint") {
|
|
@@ -25971,55 +26687,124 @@ async function quoteCommand(address, config, rest) {
|
|
|
25971
26687
|
});
|
|
25972
26688
|
return;
|
|
25973
26689
|
}
|
|
25974
|
-
printHeader(`Mint Quote — ${formatAddress(address)}`);
|
|
26690
|
+
printHeader(`Mint Quote — ${formatAddress(address)}`);
|
|
26691
|
+
console.log(`
|
|
26692
|
+
Minting ${amount} shares (${formatUnits2(shares, 18)})`);
|
|
26693
|
+
console.log();
|
|
26694
|
+
printTable([
|
|
26695
|
+
{ header: "Token", key: "token" },
|
|
26696
|
+
{ header: "Amount Required", key: "amount", align: "right" },
|
|
26697
|
+
{ header: "With 1% Slippage", key: "slippage", align: "right" }
|
|
26698
|
+
], quote.assets.map((asset, i) => ({
|
|
26699
|
+
token: formatAddress(asset),
|
|
26700
|
+
amount: quote.amounts[i].toString(),
|
|
26701
|
+
slippage: applySlippage(quote.amounts[i], slippageBps).toString()
|
|
26702
|
+
})));
|
|
26703
|
+
console.log(`
|
|
26704
|
+
Mint Fee: ${formatUnits2(quote.mintFee, 18)}`);
|
|
26705
|
+
console.log(`Min Shares Out: ${formatUnits2(quote.minSharesOut, 18)}`);
|
|
26706
|
+
} else {
|
|
26707
|
+
const quote = await readRedeemQuote2(publicClient, address, shares);
|
|
26708
|
+
if (config.json) {
|
|
26709
|
+
printJson({
|
|
26710
|
+
dtf: address,
|
|
26711
|
+
chain: config.chainId,
|
|
26712
|
+
chainLabel: chainLabel(config.chainId),
|
|
26713
|
+
action: "redeem",
|
|
26714
|
+
shares: shares.toString(),
|
|
26715
|
+
sharesHuman: Number(shares) / 1000000000000000000,
|
|
26716
|
+
amounts: quote.assets.map((asset, i) => {
|
|
26717
|
+
const token = tokenByAddress.get(asset.toLowerCase());
|
|
26718
|
+
const decimals = token?.decimals ?? 18;
|
|
26719
|
+
return {
|
|
26720
|
+
address: asset,
|
|
26721
|
+
symbol: token?.symbol ?? null,
|
|
26722
|
+
amount: quote.amounts[i].toString(),
|
|
26723
|
+
amountHuman: Number(quote.amounts[i]) / 10 ** decimals
|
|
26724
|
+
};
|
|
26725
|
+
})
|
|
26726
|
+
});
|
|
26727
|
+
return;
|
|
26728
|
+
}
|
|
26729
|
+
printHeader(`Redeem Quote — ${formatAddress(address)}`);
|
|
26730
|
+
console.log(`
|
|
26731
|
+
Redeeming ${amount} shares`);
|
|
26732
|
+
console.log();
|
|
26733
|
+
printTable([
|
|
26734
|
+
{ header: "Token", key: "token" },
|
|
26735
|
+
{ header: "Amount Out", key: "amount", align: "right" }
|
|
26736
|
+
], quote.assets.map((asset, i) => ({
|
|
26737
|
+
token: formatAddress(asset),
|
|
26738
|
+
amount: quote.amounts[i].toString()
|
|
26739
|
+
})));
|
|
26740
|
+
}
|
|
26741
|
+
}
|
|
26742
|
+
async function yieldQuote(publicClient, address, config, shares, action) {
|
|
26743
|
+
const facadeAddress = FACADE_READ_ADDRESS[config.chainId];
|
|
26744
|
+
if (!facadeAddress) {
|
|
26745
|
+
throw new Error(`No FacadeRead address for chain ${config.chainId}`);
|
|
26746
|
+
}
|
|
26747
|
+
if (action === "mint") {
|
|
26748
|
+
const quote = await readIssueQuote(publicClient, facadeAddress, address, shares);
|
|
26749
|
+
if (config.json) {
|
|
26750
|
+
printJson({
|
|
26751
|
+
dtf: address,
|
|
26752
|
+
type: "yield",
|
|
26753
|
+
chain: config.chainId,
|
|
26754
|
+
chainLabel: chainLabel(config.chainId),
|
|
26755
|
+
action: "mint",
|
|
26756
|
+
shares: shares.toString(),
|
|
26757
|
+
sharesHuman: Number(shares) / 1000000000000000000,
|
|
26758
|
+
tokens: quote.tokens.map((token, i) => ({
|
|
26759
|
+
address: token,
|
|
26760
|
+
deposit: quote.deposits[i].toString(),
|
|
26761
|
+
depositUoA: quote.depositsUoA[i].toString()
|
|
26762
|
+
}))
|
|
26763
|
+
});
|
|
26764
|
+
return;
|
|
26765
|
+
}
|
|
26766
|
+
printHeader(`Yield DTF Issue Quote — ${formatAddress(address)}`);
|
|
25975
26767
|
console.log(`
|
|
25976
|
-
|
|
26768
|
+
Issuing ${Number(shares) / 1000000000000000000} RTokens`);
|
|
25977
26769
|
console.log();
|
|
25978
26770
|
printTable([
|
|
25979
26771
|
{ header: "Token", key: "token" },
|
|
25980
|
-
{ header: "
|
|
25981
|
-
|
|
25982
|
-
|
|
25983
|
-
|
|
25984
|
-
amount: quote.amounts[i].toString(),
|
|
25985
|
-
slippage: applySlippage(quote.amounts[i], slippageBps).toString()
|
|
26772
|
+
{ header: "Deposit Required", key: "deposit", align: "right" }
|
|
26773
|
+
], quote.tokens.map((token, i) => ({
|
|
26774
|
+
token: formatAddress(token),
|
|
26775
|
+
deposit: quote.deposits[i].toString()
|
|
25986
26776
|
})));
|
|
25987
|
-
console.log(`
|
|
25988
|
-
Mint Fee: ${formatUnits2(quote.mintFee, 18)}`);
|
|
25989
|
-
console.log(`Min Shares Out: ${formatUnits2(quote.minSharesOut, 18)}`);
|
|
25990
26777
|
} else {
|
|
25991
|
-
const quote = await readRedeemQuote(publicClient, address, shares);
|
|
26778
|
+
const quote = await readRedeemQuote(publicClient, facadeAddress, address, shares);
|
|
25992
26779
|
if (config.json) {
|
|
25993
26780
|
printJson({
|
|
25994
26781
|
dtf: address,
|
|
26782
|
+
type: "yield",
|
|
25995
26783
|
chain: config.chainId,
|
|
25996
26784
|
chainLabel: chainLabel(config.chainId),
|
|
25997
26785
|
action: "redeem",
|
|
25998
26786
|
shares: shares.toString(),
|
|
25999
26787
|
sharesHuman: Number(shares) / 1000000000000000000,
|
|
26000
|
-
|
|
26001
|
-
|
|
26002
|
-
|
|
26003
|
-
|
|
26004
|
-
|
|
26005
|
-
symbol: token?.symbol ?? null,
|
|
26006
|
-
amount: quote.amounts[i].toString(),
|
|
26007
|
-
amountHuman: Number(quote.amounts[i]) / 10 ** decimals
|
|
26008
|
-
};
|
|
26009
|
-
})
|
|
26788
|
+
tokens: quote.tokens.map((token, i) => ({
|
|
26789
|
+
address: token,
|
|
26790
|
+
withdrawal: quote.withdrawals[i].toString(),
|
|
26791
|
+
available: quote.available[i].toString()
|
|
26792
|
+
}))
|
|
26010
26793
|
});
|
|
26011
26794
|
return;
|
|
26012
26795
|
}
|
|
26013
|
-
printHeader(`Redeem Quote — ${formatAddress(address)}`);
|
|
26796
|
+
printHeader(`Yield DTF Redeem Quote — ${formatAddress(address)}`);
|
|
26014
26797
|
console.log(`
|
|
26015
|
-
Redeeming ${
|
|
26798
|
+
Redeeming ${Number(shares) / 1000000000000000000} RTokens`);
|
|
26016
26799
|
console.log();
|
|
26017
26800
|
printTable([
|
|
26018
26801
|
{ header: "Token", key: "token" },
|
|
26019
|
-
{ header: "
|
|
26020
|
-
|
|
26021
|
-
|
|
26022
|
-
|
|
26802
|
+
{ header: "Withdrawal", key: "withdrawal", align: "right" },
|
|
26803
|
+
{ header: "Available", key: "available", align: "right" }
|
|
26804
|
+
], quote.tokens.map((token, i) => ({
|
|
26805
|
+
token: formatAddress(token),
|
|
26806
|
+
withdrawal: quote.withdrawals[i].toString(),
|
|
26807
|
+
available: quote.available[i].toString()
|
|
26023
26808
|
})));
|
|
26024
26809
|
}
|
|
26025
26810
|
}
|
|
@@ -26030,6 +26815,11 @@ async function feesCommand(address, config) {
|
|
|
26030
26815
|
chainId: config.chainId,
|
|
26031
26816
|
rpc: config.rpc
|
|
26032
26817
|
});
|
|
26818
|
+
const dtfType = await resolveDtfType(publicClient, address, config.dtfType);
|
|
26819
|
+
if (dtfType === "yield") {
|
|
26820
|
+
await yieldFees(publicClient, address, config);
|
|
26821
|
+
return;
|
|
26822
|
+
}
|
|
26033
26823
|
const [pending, recipients, mintFee, dtfConfig] = await Promise.all([
|
|
26034
26824
|
readPendingFees(publicClient, address),
|
|
26035
26825
|
readFeeRecipients(publicClient, address),
|
|
@@ -26102,6 +26892,39 @@ Fee Recipients:`);
|
|
|
26102
26892
|
})));
|
|
26103
26893
|
}
|
|
26104
26894
|
}
|
|
26895
|
+
async function yieldFees(publicClient, address, config) {
|
|
26896
|
+
const yieldConfig = await fetchYieldDtfConfigCached(fetchYieldDtfConfig, publicClient, config.chainId, address);
|
|
26897
|
+
const total = Number(yieldConfig.rTokenTotal) + Number(yieldConfig.rsrTotal);
|
|
26898
|
+
const holdersPct = total > 0 ? Number(yieldConfig.rTokenTotal) / total : 0;
|
|
26899
|
+
const stakersPct = total > 0 ? Number(yieldConfig.rsrTotal) / total : 0;
|
|
26900
|
+
if (config.json) {
|
|
26901
|
+
printJson({
|
|
26902
|
+
dtf: address,
|
|
26903
|
+
type: "yield",
|
|
26904
|
+
chain: config.chainId,
|
|
26905
|
+
chainLabel: chainLabel(config.chainId),
|
|
26906
|
+
distribution: {
|
|
26907
|
+
rTokenTotal: yieldConfig.rTokenTotal.toString(),
|
|
26908
|
+
rsrTotal: yieldConfig.rsrTotal.toString(),
|
|
26909
|
+
holdersPercent: holdersPct * 100,
|
|
26910
|
+
stakersPercent: stakersPct * 100
|
|
26911
|
+
}
|
|
26912
|
+
});
|
|
26913
|
+
return;
|
|
26914
|
+
}
|
|
26915
|
+
printHeader(`Yield DTF Revenue Distribution — ${yieldConfig.symbol} (${chainLabel(config.chainId)})`);
|
|
26916
|
+
console.log();
|
|
26917
|
+
printTable([
|
|
26918
|
+
{ header: "Destination", key: "dest" },
|
|
26919
|
+
{ header: "Share", key: "share", align: "right" },
|
|
26920
|
+
{ header: "Basis Points", key: "bps", align: "right" }
|
|
26921
|
+
], [
|
|
26922
|
+
{ dest: "RToken Holders (Furnace)", share: formatPct(holdersPct), bps: yieldConfig.rTokenTotal.toString() },
|
|
26923
|
+
{ dest: "RSR Stakers (StRSR)", share: formatPct(stakersPct), bps: yieldConfig.rsrTotal.toString() }
|
|
26924
|
+
]);
|
|
26925
|
+
console.log();
|
|
26926
|
+
console.log("Revenue comes from collateral yield, distributed via Furnace (melting) and StRSR rewards.");
|
|
26927
|
+
}
|
|
26105
26928
|
|
|
26106
26929
|
// src/commands/governance.ts
|
|
26107
26930
|
async function governanceCommand(address, config) {
|
|
@@ -26109,6 +26932,11 @@ async function governanceCommand(address, config) {
|
|
|
26109
26932
|
chainId: config.chainId,
|
|
26110
26933
|
rpc: config.rpc
|
|
26111
26934
|
});
|
|
26935
|
+
const dtfType = await resolveDtfType(publicClient, address, config.dtfType);
|
|
26936
|
+
if (dtfType === "yield") {
|
|
26937
|
+
await yieldGovernance(address, config);
|
|
26938
|
+
return;
|
|
26939
|
+
}
|
|
26112
26940
|
const dtfConfig = await fetchDtfConfigCached(fetchDtfConfig, publicClient, config.chainId, address);
|
|
26113
26941
|
const govs = [];
|
|
26114
26942
|
if (dtfConfig.ownerGovernance) {
|
|
@@ -26197,6 +27025,62 @@ ${g.label} Governance:`);
|
|
|
26197
27025
|
]);
|
|
26198
27026
|
}
|
|
26199
27027
|
}
|
|
27028
|
+
async function yieldGovernance(address, config) {
|
|
27029
|
+
const subgraphUrl = YIELD_SUBGRAPH_URLS[config.chainId];
|
|
27030
|
+
if (!subgraphUrl) {
|
|
27031
|
+
const msg = `Yield DTF governance not available for chain ${config.chainId} (no subgraph).`;
|
|
27032
|
+
if (config.json) {
|
|
27033
|
+
printJson({ dtf: address, type: "yield", chain: config.chainId, governances: [], message: msg });
|
|
27034
|
+
} else {
|
|
27035
|
+
console.log(msg);
|
|
27036
|
+
}
|
|
27037
|
+
return;
|
|
27038
|
+
}
|
|
27039
|
+
const query = `{
|
|
27040
|
+
rtoken(id: "${address.toLowerCase()}") {
|
|
27041
|
+
id
|
|
27042
|
+
governance {
|
|
27043
|
+
id
|
|
27044
|
+
governor
|
|
27045
|
+
timelock
|
|
27046
|
+
}
|
|
27047
|
+
}
|
|
27048
|
+
}`;
|
|
27049
|
+
try {
|
|
27050
|
+
const data = await querySubgraph(config.chainId, query, {}, subgraphUrl);
|
|
27051
|
+
const gov = data.rtoken?.governance;
|
|
27052
|
+
if (config.json) {
|
|
27053
|
+
printJson({
|
|
27054
|
+
dtf: address,
|
|
27055
|
+
type: "yield",
|
|
27056
|
+
chain: config.chainId,
|
|
27057
|
+
chainLabel: chainLabel(config.chainId),
|
|
27058
|
+
governance: gov ? { governor: gov.governor, timelock: gov.timelock } : null
|
|
27059
|
+
});
|
|
27060
|
+
return;
|
|
27061
|
+
}
|
|
27062
|
+
printHeader(`Yield DTF Governance — ${formatAddress(address)} (${chainLabel(config.chainId)})`);
|
|
27063
|
+
console.log();
|
|
27064
|
+
if (gov) {
|
|
27065
|
+
printTable([
|
|
27066
|
+
{ header: "Property", key: "prop" },
|
|
27067
|
+
{ header: "Value", key: "value" }
|
|
27068
|
+
], [
|
|
27069
|
+
{ prop: "Governor", value: gov.governor },
|
|
27070
|
+
{ prop: "Timelock", value: gov.timelock }
|
|
27071
|
+
]);
|
|
27072
|
+
} else {
|
|
27073
|
+
console.log("No governance found for this yield DTF.");
|
|
27074
|
+
}
|
|
27075
|
+
} catch {
|
|
27076
|
+
const msg = "Failed to fetch yield DTF governance from subgraph.";
|
|
27077
|
+
if (config.json) {
|
|
27078
|
+
printJson({ dtf: address, type: "yield", chain: config.chainId, governance: null, error: msg });
|
|
27079
|
+
} else {
|
|
27080
|
+
console.log(msg);
|
|
27081
|
+
}
|
|
27082
|
+
}
|
|
27083
|
+
}
|
|
26200
27084
|
|
|
26201
27085
|
// src/commands/staking.ts
|
|
26202
27086
|
async function stakingCommand(address, config, rest) {
|
|
@@ -26204,6 +27088,11 @@ async function stakingCommand(address, config, rest) {
|
|
|
26204
27088
|
chainId: config.chainId,
|
|
26205
27089
|
rpc: config.rpc
|
|
26206
27090
|
});
|
|
27091
|
+
const dtfType = await resolveDtfType(publicClient, address, config.dtfType);
|
|
27092
|
+
if (dtfType === "yield") {
|
|
27093
|
+
await yieldStaking(publicClient, address, config);
|
|
27094
|
+
return;
|
|
27095
|
+
}
|
|
26207
27096
|
const dtfConfig = await fetchDtfConfigCached(fetchDtfConfig, publicClient, config.chainId, address);
|
|
26208
27097
|
const stToken = dtfConfig.stTokenAddress;
|
|
26209
27098
|
if (!stToken) {
|
|
@@ -26290,6 +27179,59 @@ Account: ${account}`);
|
|
|
26290
27179
|
]);
|
|
26291
27180
|
}
|
|
26292
27181
|
}
|
|
27182
|
+
async function yieldStaking(publicClient, address, config) {
|
|
27183
|
+
const yieldConfig = await fetchYieldDtfConfigCached(fetchYieldDtfConfig, publicClient, config.chainId, address);
|
|
27184
|
+
const account = config.account;
|
|
27185
|
+
const stRSRInfo = await readStRSRInfo(publicClient, yieldConfig.components.stRSR, account);
|
|
27186
|
+
const exchangeRate = Number(stRSRInfo.exchangeRate) / Number(D18);
|
|
27187
|
+
if (config.json) {
|
|
27188
|
+
printJson({
|
|
27189
|
+
dtf: address,
|
|
27190
|
+
type: "yield",
|
|
27191
|
+
chain: config.chainId,
|
|
27192
|
+
chainLabel: chainLabel(config.chainId),
|
|
27193
|
+
stRSR: yieldConfig.components.stRSR,
|
|
27194
|
+
exchangeRate: stRSRInfo.exchangeRate.toString(),
|
|
27195
|
+
exchangeRateHuman: exchangeRate,
|
|
27196
|
+
totalSupply: stRSRInfo.totalSupply.toString(),
|
|
27197
|
+
totalSupplyHuman: Number(stRSRInfo.totalSupply) / 1000000000000000000,
|
|
27198
|
+
unstakingDelay: stRSRInfo.unstakingDelay.toString(),
|
|
27199
|
+
unstakingDelayHuman: formatDuration(Number(stRSRInfo.unstakingDelay)),
|
|
27200
|
+
account: account && stRSRInfo.balance !== undefined ? {
|
|
27201
|
+
address: account,
|
|
27202
|
+
balance: stRSRInfo.balance.toString(),
|
|
27203
|
+
balanceHuman: Number(stRSRInfo.balance) / 1000000000000000000,
|
|
27204
|
+
votingPower: stRSRInfo.votingPower.toString(),
|
|
27205
|
+
votingPowerHuman: Number(stRSRInfo.votingPower) / 1000000000000000000,
|
|
27206
|
+
delegatee: stRSRInfo.delegatee
|
|
27207
|
+
} : null
|
|
27208
|
+
});
|
|
27209
|
+
return;
|
|
27210
|
+
}
|
|
27211
|
+
printHeader(`Yield DTF Staking — ${yieldConfig.symbol} (${chainLabel(config.chainId)})`);
|
|
27212
|
+
console.log();
|
|
27213
|
+
printTable([
|
|
27214
|
+
{ header: "Property", key: "prop" },
|
|
27215
|
+
{ header: "Value", key: "value" }
|
|
27216
|
+
], [
|
|
27217
|
+
{ prop: "StRSR Address", value: yieldConfig.components.stRSR },
|
|
27218
|
+
{ prop: "Exchange Rate", value: `${exchangeRate.toFixed(6)} RSR/stRSR` },
|
|
27219
|
+
{ prop: "Total Supply", value: `${(Number(stRSRInfo.totalSupply) / 1000000000000000000).toLocaleString("en-US", { maximumFractionDigits: 2 })} stRSR` },
|
|
27220
|
+
{ prop: "Unstaking Delay", value: formatDuration(Number(stRSRInfo.unstakingDelay)) }
|
|
27221
|
+
]);
|
|
27222
|
+
if (account && stRSRInfo.balance !== undefined) {
|
|
27223
|
+
console.log(`
|
|
27224
|
+
Account: ${account}`);
|
|
27225
|
+
printTable([
|
|
27226
|
+
{ header: "Property", key: "prop" },
|
|
27227
|
+
{ header: "Value", key: "value", align: "right" }
|
|
27228
|
+
], [
|
|
27229
|
+
{ prop: "Balance", value: formatUnits2(stRSRInfo.balance, 18) },
|
|
27230
|
+
{ prop: "Voting Power", value: formatUnits2(stRSRInfo.votingPower, 18) },
|
|
27231
|
+
{ prop: "Delegatee", value: stRSRInfo.delegatee }
|
|
27232
|
+
]);
|
|
27233
|
+
}
|
|
27234
|
+
}
|
|
26293
27235
|
|
|
26294
27236
|
// src/commands/roles.ts
|
|
26295
27237
|
async function rolesCommand(address, config) {
|
|
@@ -26297,6 +27239,11 @@ async function rolesCommand(address, config) {
|
|
|
26297
27239
|
chainId: config.chainId,
|
|
26298
27240
|
rpc: config.rpc
|
|
26299
27241
|
});
|
|
27242
|
+
const dtfType = await resolveDtfType(publicClient, address, config.dtfType);
|
|
27243
|
+
if (dtfType === "yield") {
|
|
27244
|
+
await yieldRoles(address, config);
|
|
27245
|
+
return;
|
|
27246
|
+
}
|
|
26300
27247
|
const dtfConfig = await fetchDtfConfigCached(fetchDtfConfig, publicClient, config.chainId, address);
|
|
26301
27248
|
if (config.json) {
|
|
26302
27249
|
printJson({
|
|
@@ -26341,6 +27288,63 @@ async function rolesCommand(address, config) {
|
|
|
26341
27288
|
{ header: "Holder", key: "holder" }
|
|
26342
27289
|
], rows);
|
|
26343
27290
|
}
|
|
27291
|
+
async function yieldRoles(address, config) {
|
|
27292
|
+
const subgraphUrl = YIELD_SUBGRAPH_URLS[config.chainId];
|
|
27293
|
+
if (!subgraphUrl) {
|
|
27294
|
+
const msg = `Yield DTF roles not available for chain ${config.chainId} (no subgraph).`;
|
|
27295
|
+
if (config.json) {
|
|
27296
|
+
printJson({ dtf: address, type: "yield", chain: config.chainId, roles: null, message: msg });
|
|
27297
|
+
} else {
|
|
27298
|
+
console.log(msg);
|
|
27299
|
+
}
|
|
27300
|
+
return;
|
|
27301
|
+
}
|
|
27302
|
+
const query = `{
|
|
27303
|
+
rtoken(id: "${address.toLowerCase()}") {
|
|
27304
|
+
id
|
|
27305
|
+
main {
|
|
27306
|
+
owner
|
|
27307
|
+
pauser
|
|
27308
|
+
freezer
|
|
27309
|
+
}
|
|
27310
|
+
}
|
|
27311
|
+
}`;
|
|
27312
|
+
try {
|
|
27313
|
+
const data = await querySubgraph(config.chainId, query, {}, subgraphUrl);
|
|
27314
|
+
const main = data.rtoken?.main;
|
|
27315
|
+
if (config.json) {
|
|
27316
|
+
printJson({
|
|
27317
|
+
dtf: address,
|
|
27318
|
+
type: "yield",
|
|
27319
|
+
chain: config.chainId,
|
|
27320
|
+
chainLabel: chainLabel(config.chainId),
|
|
27321
|
+
roles: main ? { owner: main.owner, pauser: main.pauser, freezer: main.freezer } : null
|
|
27322
|
+
});
|
|
27323
|
+
return;
|
|
27324
|
+
}
|
|
27325
|
+
printHeader(`Yield DTF Roles — ${formatAddress(address)} (${chainLabel(config.chainId)})`);
|
|
27326
|
+
console.log();
|
|
27327
|
+
if (main) {
|
|
27328
|
+
printTable([
|
|
27329
|
+
{ header: "Role", key: "role" },
|
|
27330
|
+
{ header: "Holder", key: "holder" }
|
|
27331
|
+
], [
|
|
27332
|
+
{ role: "Owner", holder: main.owner },
|
|
27333
|
+
{ role: "Pauser", holder: main.pauser },
|
|
27334
|
+
{ role: "Freezer", holder: main.freezer }
|
|
27335
|
+
]);
|
|
27336
|
+
} else {
|
|
27337
|
+
console.log("No role data found for this yield DTF.");
|
|
27338
|
+
}
|
|
27339
|
+
} catch {
|
|
27340
|
+
const msg = "Failed to fetch yield DTF roles from subgraph.";
|
|
27341
|
+
if (config.json) {
|
|
27342
|
+
printJson({ dtf: address, type: "yield", chain: config.chainId, roles: null, error: msg });
|
|
27343
|
+
} else {
|
|
27344
|
+
console.log(msg);
|
|
27345
|
+
}
|
|
27346
|
+
}
|
|
27347
|
+
}
|
|
26344
27348
|
|
|
26345
27349
|
// src/commands/rebalance-history.ts
|
|
26346
27350
|
function summarizeRebalance(detail) {
|
|
@@ -26571,19 +27575,6 @@ function computeReturn(performance) {
|
|
|
26571
27575
|
return null;
|
|
26572
27576
|
return Math.round((last.value - first.value) / first.value * 1e4) / 100;
|
|
26573
27577
|
}
|
|
26574
|
-
var PERIOD_SECONDS = {
|
|
26575
|
-
"30d": 30 * 24 * 60 * 60,
|
|
26576
|
-
"3m": 90 * 24 * 60 * 60,
|
|
26577
|
-
"6m": 180 * 24 * 60 * 60,
|
|
26578
|
-
"1y": 365 * 24 * 60 * 60
|
|
26579
|
-
};
|
|
26580
|
-
function parsePeriodSeconds(period) {
|
|
26581
|
-
const s = PERIOD_SECONDS[period];
|
|
26582
|
-
if (!s) {
|
|
26583
|
-
throw new Error(`Unknown period "${period}". Use: 30d, 3m, 6m, 1y`);
|
|
26584
|
-
}
|
|
26585
|
-
return s;
|
|
26586
|
-
}
|
|
26587
27578
|
async function discoverCommand(config) {
|
|
26588
27579
|
const isAll = config.allChains || !config.chainExplicit;
|
|
26589
27580
|
const chains = isAll ? [...SUPPORTED_CHAINS] : [config.chainId];
|
|
@@ -27695,9 +28686,492 @@ function getFlag2(args, flag) {
|
|
|
27695
28686
|
return args[idx + 1];
|
|
27696
28687
|
}
|
|
27697
28688
|
|
|
28689
|
+
// src/commands/query.ts
|
|
28690
|
+
var INDEX_ONLY = new Set([
|
|
28691
|
+
"dtf",
|
|
28692
|
+
"dtfs",
|
|
28693
|
+
"rebalance",
|
|
28694
|
+
"rebalances",
|
|
28695
|
+
"auction",
|
|
28696
|
+
"auctions",
|
|
28697
|
+
"auctionBid",
|
|
28698
|
+
"auctionBids",
|
|
28699
|
+
"rebalanceAuctionBid",
|
|
28700
|
+
"rebalanceAuctionBids",
|
|
28701
|
+
"stakingToken",
|
|
28702
|
+
"stakingTokens",
|
|
28703
|
+
"stakingTokenRewards",
|
|
28704
|
+
"lock",
|
|
28705
|
+
"locks",
|
|
28706
|
+
"rsrBurn",
|
|
28707
|
+
"rsrBurns",
|
|
28708
|
+
"rsrBurnGlobal",
|
|
28709
|
+
"rsrBurnDailySnapshot",
|
|
28710
|
+
"rsrBurnDailySnapshots",
|
|
28711
|
+
"rsrBurnMonthlySnapshot",
|
|
28712
|
+
"rsrBurnMonthlySnapshots",
|
|
28713
|
+
"minting",
|
|
28714
|
+
"mintings",
|
|
28715
|
+
"transferEvent",
|
|
28716
|
+
"transferEvents",
|
|
28717
|
+
"unstakingManager",
|
|
28718
|
+
"version",
|
|
28719
|
+
"versions",
|
|
28720
|
+
"timelockOperation",
|
|
28721
|
+
"timelockOperations",
|
|
28722
|
+
"timelockOperationByTx"
|
|
28723
|
+
]);
|
|
28724
|
+
var YIELD_ONLY = new Set([
|
|
28725
|
+
"rtoken",
|
|
28726
|
+
"rtokens",
|
|
28727
|
+
"protocol",
|
|
28728
|
+
"protocols",
|
|
28729
|
+
"accountRToken",
|
|
28730
|
+
"accountRTokens",
|
|
28731
|
+
"accountRTokenDailySnapshot",
|
|
28732
|
+
"accountRTokenDailySnapshots",
|
|
28733
|
+
"accountStakeRecord",
|
|
28734
|
+
"accountStakeRecords",
|
|
28735
|
+
"governanceFramework",
|
|
28736
|
+
"governanceFrameworks",
|
|
28737
|
+
"revenueDistribution",
|
|
28738
|
+
"revenueDistributions",
|
|
28739
|
+
"financialsDailySnapshot",
|
|
28740
|
+
"financialsDailySnapshots",
|
|
28741
|
+
"rtokenDailySnapshot",
|
|
28742
|
+
"rtokenDailySnapshots",
|
|
28743
|
+
"rtokenHourlySnapshot",
|
|
28744
|
+
"rtokenHourlySnapshots",
|
|
28745
|
+
"rtokenHistoricalBaskets",
|
|
28746
|
+
"deployer",
|
|
28747
|
+
"deployers",
|
|
28748
|
+
"collateral",
|
|
28749
|
+
"collaterals",
|
|
28750
|
+
"stTokenDailySnapshot",
|
|
28751
|
+
"stTokenDailySnapshots",
|
|
28752
|
+
"rewardToken",
|
|
28753
|
+
"rewardTokens",
|
|
28754
|
+
"tokenHolder",
|
|
28755
|
+
"tokenHolders",
|
|
28756
|
+
"usageMetricsDailySnapshot",
|
|
28757
|
+
"usageMetricsDailySnapshots",
|
|
28758
|
+
"usageMetricsHourlySnapshot",
|
|
28759
|
+
"usageMetricsHourlySnapshots",
|
|
28760
|
+
"rtokenContract",
|
|
28761
|
+
"rtokenContracts",
|
|
28762
|
+
"entry",
|
|
28763
|
+
"entries",
|
|
28764
|
+
"activeAccount",
|
|
28765
|
+
"activeAccounts"
|
|
28766
|
+
]);
|
|
28767
|
+
var SHARED = new Set([
|
|
28768
|
+
"account",
|
|
28769
|
+
"accounts",
|
|
28770
|
+
"accountBalance",
|
|
28771
|
+
"accountBalances",
|
|
28772
|
+
"accountBalanceDailySnapshot",
|
|
28773
|
+
"accountBalanceDailySnapshots",
|
|
28774
|
+
"token",
|
|
28775
|
+
"tokens",
|
|
28776
|
+
"tokenDailySnapshot",
|
|
28777
|
+
"tokenDailySnapshots",
|
|
28778
|
+
"tokenHourlySnapshot",
|
|
28779
|
+
"tokenHourlySnapshots",
|
|
28780
|
+
"tokenMonthlySnapshot",
|
|
28781
|
+
"tokenMonthlySnapshots",
|
|
28782
|
+
"proposal",
|
|
28783
|
+
"proposals",
|
|
28784
|
+
"vote",
|
|
28785
|
+
"votes",
|
|
28786
|
+
"delegate",
|
|
28787
|
+
"delegates",
|
|
28788
|
+
"delegateChange",
|
|
28789
|
+
"delegateChanges",
|
|
28790
|
+
"delegateVotingPowerChange",
|
|
28791
|
+
"delegateVotingPowerChanges",
|
|
28792
|
+
"governance",
|
|
28793
|
+
"governances",
|
|
28794
|
+
"governanceTimelock",
|
|
28795
|
+
"governanceTimelocks",
|
|
28796
|
+
"trade",
|
|
28797
|
+
"trades",
|
|
28798
|
+
"voteDailySnapshot",
|
|
28799
|
+
"voteDailySnapshots"
|
|
28800
|
+
]);
|
|
28801
|
+
function extractRootEntities(query) {
|
|
28802
|
+
const firstBrace = query.indexOf("{");
|
|
28803
|
+
if (firstBrace === -1)
|
|
28804
|
+
return [];
|
|
28805
|
+
const bodyStart = firstBrace + 1;
|
|
28806
|
+
const body = query.slice(bodyStart);
|
|
28807
|
+
const entities = [];
|
|
28808
|
+
let braceDepth = 0;
|
|
28809
|
+
let parenDepth = 0;
|
|
28810
|
+
const tokenRegex = /(\w+)|([{}()])/g;
|
|
28811
|
+
let match;
|
|
28812
|
+
while ((match = tokenRegex.exec(body)) !== null) {
|
|
28813
|
+
if (match[2] === "{")
|
|
28814
|
+
braceDepth++;
|
|
28815
|
+
else if (match[2] === "}")
|
|
28816
|
+
braceDepth--;
|
|
28817
|
+
else if (match[2] === "(")
|
|
28818
|
+
parenDepth++;
|
|
28819
|
+
else if (match[2] === ")")
|
|
28820
|
+
parenDepth--;
|
|
28821
|
+
else if (match[1] && braceDepth === 0 && parenDepth === 0) {
|
|
28822
|
+
entities.push(match[1]);
|
|
28823
|
+
}
|
|
28824
|
+
}
|
|
28825
|
+
return entities;
|
|
28826
|
+
}
|
|
28827
|
+
function detectSubgraph(query) {
|
|
28828
|
+
const entities = extractRootEntities(query);
|
|
28829
|
+
let hasIndex = false;
|
|
28830
|
+
let hasYield = false;
|
|
28831
|
+
let hasShared = false;
|
|
28832
|
+
let hasUnknown = false;
|
|
28833
|
+
for (const entity of entities) {
|
|
28834
|
+
if (INDEX_ONLY.has(entity))
|
|
28835
|
+
hasIndex = true;
|
|
28836
|
+
else if (YIELD_ONLY.has(entity))
|
|
28837
|
+
hasYield = true;
|
|
28838
|
+
else if (SHARED.has(entity))
|
|
28839
|
+
hasShared = true;
|
|
28840
|
+
else
|
|
28841
|
+
hasUnknown = true;
|
|
28842
|
+
}
|
|
28843
|
+
if (hasIndex && hasYield) {
|
|
28844
|
+
throw new Error("Query contains both index-only and yield-only entities. Use --subgraph to specify which subgraph to query.");
|
|
28845
|
+
}
|
|
28846
|
+
if (hasYield)
|
|
28847
|
+
return { subgraph: "yield" };
|
|
28848
|
+
if (hasIndex)
|
|
28849
|
+
return { subgraph: "index" };
|
|
28850
|
+
return {
|
|
28851
|
+
subgraph: "index",
|
|
28852
|
+
note: "Auto-detected as index subgraph. Use --subgraph yield to query the yield subgraph instead."
|
|
28853
|
+
};
|
|
28854
|
+
}
|
|
28855
|
+
var YIELD_CHAINS = Object.keys(YIELD_SUBGRAPH_URLS).map(Number);
|
|
28856
|
+
async function queryCommand(config, rest) {
|
|
28857
|
+
const query = rest[0];
|
|
28858
|
+
if (!query) {
|
|
28859
|
+
throw new Error("Usage: dtf query '<graphql>' [--subgraph index|yield] [--chain <id|all>]");
|
|
28860
|
+
}
|
|
28861
|
+
let subgraph;
|
|
28862
|
+
let note;
|
|
28863
|
+
if (config.subgraph) {
|
|
28864
|
+
subgraph = config.subgraph;
|
|
28865
|
+
} else {
|
|
28866
|
+
const detected = detectSubgraph(query);
|
|
28867
|
+
subgraph = detected.subgraph;
|
|
28868
|
+
note = detected.note;
|
|
28869
|
+
}
|
|
28870
|
+
const getUrl2 = (chainId) => {
|
|
28871
|
+
if (subgraph === "yield") {
|
|
28872
|
+
const url = YIELD_SUBGRAPH_URLS[chainId];
|
|
28873
|
+
if (!url)
|
|
28874
|
+
throw new Error(`No yield subgraph for chain ${chainId}. Yield DTFs are only on Ethereum (1) and Base (8453).`);
|
|
28875
|
+
return url;
|
|
28876
|
+
}
|
|
28877
|
+
return SUBGRAPH_URLS[chainId];
|
|
28878
|
+
};
|
|
28879
|
+
if (config.allChains) {
|
|
28880
|
+
const chains = subgraph === "yield" ? YIELD_CHAINS : SUPPORTED_CHAINS;
|
|
28881
|
+
const results = await Promise.allSettled(chains.map(async (chainId) => {
|
|
28882
|
+
const url = getUrl2(chainId);
|
|
28883
|
+
const data = await querySubgraph(chainId, query, {}, url);
|
|
28884
|
+
return { chain: chainId, chainLabel: chainLabel(chainId), data };
|
|
28885
|
+
}));
|
|
28886
|
+
const output = results.map((r, i) => {
|
|
28887
|
+
if (r.status === "fulfilled")
|
|
28888
|
+
return r.value;
|
|
28889
|
+
return { chain: chains[i], chainLabel: chainLabel(chains[i]), error: String(r.reason) };
|
|
28890
|
+
});
|
|
28891
|
+
printJson({ subgraph, ...note ? { note } : {}, results: output });
|
|
28892
|
+
} else {
|
|
28893
|
+
const url = getUrl2(config.chainId);
|
|
28894
|
+
const data = await querySubgraph(config.chainId, query, {}, url);
|
|
28895
|
+
printJson({ subgraph, chain: config.chainId, chainLabel: chainLabel(config.chainId), ...note ? { note } : {}, data });
|
|
28896
|
+
}
|
|
28897
|
+
}
|
|
28898
|
+
|
|
28899
|
+
// src/commands/holders.ts
|
|
28900
|
+
async function holdersCommand(address, config) {
|
|
28901
|
+
const { publicClient } = createDtfClients({ chainId: config.chainId, rpc: config.rpc });
|
|
28902
|
+
const dtfType = await resolveDtfType(publicClient, address, config.dtfType);
|
|
28903
|
+
const limit = config.limit ?? 20;
|
|
28904
|
+
const addrLower = address.toLowerCase();
|
|
28905
|
+
if (dtfType === "yield") {
|
|
28906
|
+
await yieldHolders(addrLower, config, limit);
|
|
28907
|
+
} else {
|
|
28908
|
+
await indexHolders(addrLower, config, limit);
|
|
28909
|
+
}
|
|
28910
|
+
}
|
|
28911
|
+
async function indexHolders(address, config, limit) {
|
|
28912
|
+
const query = `{
|
|
28913
|
+
token(id: "${address}") { currentHolderCount decimals }
|
|
28914
|
+
accountBalances(
|
|
28915
|
+
where: { token: "${address}", amount_gt: "0" }
|
|
28916
|
+
orderBy: amount, orderDirection: desc
|
|
28917
|
+
first: ${limit}
|
|
28918
|
+
) {
|
|
28919
|
+
account { id }
|
|
28920
|
+
amount
|
|
28921
|
+
delegate { address }
|
|
28922
|
+
}
|
|
28923
|
+
}`;
|
|
28924
|
+
const chainId = config.chainId;
|
|
28925
|
+
const url = SUBGRAPH_URLS[chainId];
|
|
28926
|
+
const [data, prices] = await Promise.all([
|
|
28927
|
+
querySubgraph(chainId, query, {}, url),
|
|
28928
|
+
fetchTokenPrices(chainId, [address]).catch(() => ({}))
|
|
28929
|
+
]);
|
|
28930
|
+
const decimals = data.token?.decimals ?? 18;
|
|
28931
|
+
const totalHolders = data.token?.currentHolderCount ?? 0;
|
|
28932
|
+
const tokenPrice = prices[address] ?? 0;
|
|
28933
|
+
const holders = data.accountBalances.map((h, i) => {
|
|
28934
|
+
const balance = Number(h.amount) / 10 ** decimals;
|
|
28935
|
+
return {
|
|
28936
|
+
account: h.account.id,
|
|
28937
|
+
balance: h.amount,
|
|
28938
|
+
balanceHuman: balance,
|
|
28939
|
+
balanceUsd: balance * tokenPrice,
|
|
28940
|
+
delegate: h.delegate?.address,
|
|
28941
|
+
rank: i + 1
|
|
28942
|
+
};
|
|
28943
|
+
});
|
|
28944
|
+
if (config.json) {
|
|
28945
|
+
printJson({
|
|
28946
|
+
dtf: address,
|
|
28947
|
+
chain: config.chainId,
|
|
28948
|
+
chainLabel: chainLabel(config.chainId),
|
|
28949
|
+
type: "index",
|
|
28950
|
+
tokenPrice,
|
|
28951
|
+
holders,
|
|
28952
|
+
totalHolders
|
|
28953
|
+
});
|
|
28954
|
+
return;
|
|
28955
|
+
}
|
|
28956
|
+
printHeader(`Top Holders — ${formatAddress(address)} (${chainLabel(config.chainId)})`);
|
|
28957
|
+
console.log(`Total holders: ${totalHolders}`);
|
|
28958
|
+
if (tokenPrice > 0)
|
|
28959
|
+
console.log(`Token price: ${formatUsd(tokenPrice)}`);
|
|
28960
|
+
console.log();
|
|
28961
|
+
printTable([
|
|
28962
|
+
{ header: "#", key: "rank", align: "right" },
|
|
28963
|
+
{ header: "Account", key: "account" },
|
|
28964
|
+
{ header: "Balance", key: "balance", align: "right" },
|
|
28965
|
+
...tokenPrice > 0 ? [{ header: "USD", key: "usd", align: "right" }] : []
|
|
28966
|
+
], holders.map((h) => ({
|
|
28967
|
+
rank: String(h.rank),
|
|
28968
|
+
account: formatAddress(h.account),
|
|
28969
|
+
balance: h.balanceHuman.toLocaleString("en-US", { maximumFractionDigits: 2 }),
|
|
28970
|
+
usd: formatUsd(h.balanceUsd)
|
|
28971
|
+
})));
|
|
28972
|
+
}
|
|
28973
|
+
async function yieldHolders(address, config, limit) {
|
|
28974
|
+
const query = `{
|
|
28975
|
+
token(id: "${address}") { holderCount decimals lastPriceUSD }
|
|
28976
|
+
accountBalances(
|
|
28977
|
+
where: { token: "${address}", amount_gt: "0" }
|
|
28978
|
+
orderBy: amount, orderDirection: desc
|
|
28979
|
+
first: ${limit}
|
|
28980
|
+
) {
|
|
28981
|
+
account { id }
|
|
28982
|
+
amount
|
|
28983
|
+
}
|
|
28984
|
+
}`;
|
|
28985
|
+
const chainId = config.chainId;
|
|
28986
|
+
const url = YIELD_SUBGRAPH_URLS[chainId];
|
|
28987
|
+
if (!url)
|
|
28988
|
+
throw new Error(`No yield subgraph for chain ${chainId}`);
|
|
28989
|
+
const data = await querySubgraph(chainId, query, {}, url);
|
|
28990
|
+
const decimals = data.token?.decimals ?? 18;
|
|
28991
|
+
const totalHolders = data.token?.holderCount ?? 0;
|
|
28992
|
+
const tokenPrice = Number(data.token?.lastPriceUSD ?? "0");
|
|
28993
|
+
const holders = data.accountBalances.map((h, i) => {
|
|
28994
|
+
const balance = Number(h.amount) / 10 ** decimals;
|
|
28995
|
+
return {
|
|
28996
|
+
account: h.account.id,
|
|
28997
|
+
balance: h.amount,
|
|
28998
|
+
balanceHuman: balance,
|
|
28999
|
+
balanceUsd: balance * tokenPrice,
|
|
29000
|
+
rank: i + 1
|
|
29001
|
+
};
|
|
29002
|
+
});
|
|
29003
|
+
if (config.json) {
|
|
29004
|
+
printJson({
|
|
29005
|
+
dtf: address,
|
|
29006
|
+
chain: config.chainId,
|
|
29007
|
+
chainLabel: chainLabel(config.chainId),
|
|
29008
|
+
type: "yield",
|
|
29009
|
+
tokenPrice,
|
|
29010
|
+
holders,
|
|
29011
|
+
totalHolders
|
|
29012
|
+
});
|
|
29013
|
+
return;
|
|
29014
|
+
}
|
|
29015
|
+
printHeader(`Top Holders — ${formatAddress(address)} (${chainLabel(config.chainId)})`);
|
|
29016
|
+
console.log(`Total holders: ${totalHolders}`);
|
|
29017
|
+
if (tokenPrice > 0)
|
|
29018
|
+
console.log(`Token price: ${formatUsd(tokenPrice)}`);
|
|
29019
|
+
console.log();
|
|
29020
|
+
printTable([
|
|
29021
|
+
{ header: "#", key: "rank", align: "right" },
|
|
29022
|
+
{ header: "Account", key: "account" },
|
|
29023
|
+
{ header: "Balance", key: "balance", align: "right" },
|
|
29024
|
+
...tokenPrice > 0 ? [{ header: "USD", key: "usd", align: "right" }] : []
|
|
29025
|
+
], holders.map((h) => ({
|
|
29026
|
+
rank: String(h.rank),
|
|
29027
|
+
account: formatAddress(h.account),
|
|
29028
|
+
balance: h.balanceHuman.toLocaleString("en-US", { maximumFractionDigits: 2 }),
|
|
29029
|
+
usd: formatUsd(h.balanceUsd)
|
|
29030
|
+
})));
|
|
29031
|
+
}
|
|
29032
|
+
|
|
29033
|
+
// src/commands/delegates.ts
|
|
29034
|
+
async function delegatesCommand(address, config) {
|
|
29035
|
+
const { publicClient } = createDtfClients({ chainId: config.chainId, rpc: config.rpc });
|
|
29036
|
+
const dtfType = await resolveDtfType(publicClient, address, config.dtfType);
|
|
29037
|
+
const limit = config.limit ?? 20;
|
|
29038
|
+
const addrLower = address.toLowerCase();
|
|
29039
|
+
if (dtfType === "yield") {
|
|
29040
|
+
await yieldDelegates(addrLower, config, limit);
|
|
29041
|
+
} else {
|
|
29042
|
+
await indexDelegates(publicClient, addrLower, config, limit);
|
|
29043
|
+
}
|
|
29044
|
+
}
|
|
29045
|
+
async function indexDelegates(publicClient, address, config, limit) {
|
|
29046
|
+
const dtfConfig = await fetchDtfConfigCached(fetchDtfConfig, publicClient, config.chainId, address);
|
|
29047
|
+
const stTokenAddress = dtfConfig.stTokenAddress?.toLowerCase();
|
|
29048
|
+
if (!stTokenAddress) {
|
|
29049
|
+
throw new Error(`No stToken found for DTF ${address}. This DTF may not have governance.`);
|
|
29050
|
+
}
|
|
29051
|
+
const query = `{
|
|
29052
|
+
stakingToken(id: "${stTokenAddress}") {
|
|
29053
|
+
currentDelegates totalDelegates delegatedVotesRaw
|
|
29054
|
+
delegates(
|
|
29055
|
+
first: ${limit}
|
|
29056
|
+
orderBy: delegatedVotesRaw
|
|
29057
|
+
orderDirection: desc
|
|
29058
|
+
) {
|
|
29059
|
+
address
|
|
29060
|
+
delegatedVotesRaw
|
|
29061
|
+
tokenHoldersRepresentedAmount
|
|
29062
|
+
numberVotes
|
|
29063
|
+
}
|
|
29064
|
+
}
|
|
29065
|
+
}`;
|
|
29066
|
+
const chainId = config.chainId;
|
|
29067
|
+
const url = SUBGRAPH_URLS[chainId];
|
|
29068
|
+
const data = await querySubgraph(chainId, query, {}, url);
|
|
29069
|
+
if (!data.stakingToken) {
|
|
29070
|
+
throw new Error(`StakingToken ${stTokenAddress} not found in subgraph`);
|
|
29071
|
+
}
|
|
29072
|
+
const delegates = data.stakingToken.delegates.map((d, i) => ({
|
|
29073
|
+
address: d.address,
|
|
29074
|
+
delegatedVotes: d.delegatedVotesRaw,
|
|
29075
|
+
delegatedVotesHuman: Number(d.delegatedVotesRaw) / 1000000000000000000,
|
|
29076
|
+
representedHolders: d.tokenHoldersRepresentedAmount,
|
|
29077
|
+
votesCast: d.numberVotes,
|
|
29078
|
+
rank: i + 1
|
|
29079
|
+
}));
|
|
29080
|
+
if (config.json) {
|
|
29081
|
+
printJson({
|
|
29082
|
+
dtf: address,
|
|
29083
|
+
chain: config.chainId,
|
|
29084
|
+
chainLabel: chainLabel(config.chainId),
|
|
29085
|
+
type: "index",
|
|
29086
|
+
governanceToken: stTokenAddress,
|
|
29087
|
+
delegates,
|
|
29088
|
+
totalDelegates: data.stakingToken.currentDelegates
|
|
29089
|
+
});
|
|
29090
|
+
return;
|
|
29091
|
+
}
|
|
29092
|
+
printHeader(`Delegates — ${formatAddress(address)} (${chainLabel(config.chainId)})`);
|
|
29093
|
+
console.log(`Active delegates: ${data.stakingToken.currentDelegates} (${data.stakingToken.totalDelegates} total)`);
|
|
29094
|
+
console.log();
|
|
29095
|
+
printTable([
|
|
29096
|
+
{ header: "#", key: "rank", align: "right" },
|
|
29097
|
+
{ header: "Delegate", key: "delegate" },
|
|
29098
|
+
{ header: "Votes", key: "votes", align: "right" },
|
|
29099
|
+
{ header: "Holders", key: "holders", align: "right" },
|
|
29100
|
+
{ header: "Cast", key: "cast", align: "right" }
|
|
29101
|
+
], delegates.map((d) => ({
|
|
29102
|
+
rank: String(d.rank),
|
|
29103
|
+
delegate: formatAddress(d.address),
|
|
29104
|
+
votes: d.delegatedVotesHuman.toLocaleString("en-US", { maximumFractionDigits: 0 }),
|
|
29105
|
+
holders: String(d.representedHolders),
|
|
29106
|
+
cast: String(d.votesCast)
|
|
29107
|
+
})));
|
|
29108
|
+
}
|
|
29109
|
+
async function yieldDelegates(address, config, limit) {
|
|
29110
|
+
const addrLower = address.toLowerCase();
|
|
29111
|
+
const query = `{
|
|
29112
|
+
governance(id: "${addrLower}") {
|
|
29113
|
+
currentDelegates totalDelegates delegatedVotesRaw
|
|
29114
|
+
}
|
|
29115
|
+
delegates(
|
|
29116
|
+
where: { governance: "${addrLower}" }
|
|
29117
|
+
first: ${limit}
|
|
29118
|
+
orderBy: delegatedVotesRaw
|
|
29119
|
+
orderDirection: desc
|
|
29120
|
+
) {
|
|
29121
|
+
address
|
|
29122
|
+
delegatedVotesRaw
|
|
29123
|
+
tokenHoldersRepresentedAmount
|
|
29124
|
+
numberVotes
|
|
29125
|
+
}
|
|
29126
|
+
}`;
|
|
29127
|
+
const chainId = config.chainId;
|
|
29128
|
+
const url = YIELD_SUBGRAPH_URLS[chainId];
|
|
29129
|
+
if (!url)
|
|
29130
|
+
throw new Error(`No yield subgraph for chain ${chainId}`);
|
|
29131
|
+
const data = await querySubgraph(chainId, query, {}, url);
|
|
29132
|
+
const delegates = data.delegates.map((d, i) => ({
|
|
29133
|
+
address: d.address,
|
|
29134
|
+
delegatedVotes: d.delegatedVotesRaw,
|
|
29135
|
+
delegatedVotesHuman: Number(d.delegatedVotesRaw) / 1000000000000000000,
|
|
29136
|
+
representedHolders: d.tokenHoldersRepresentedAmount,
|
|
29137
|
+
votesCast: d.numberVotes,
|
|
29138
|
+
rank: i + 1
|
|
29139
|
+
}));
|
|
29140
|
+
if (config.json) {
|
|
29141
|
+
printJson({
|
|
29142
|
+
dtf: address,
|
|
29143
|
+
chain: config.chainId,
|
|
29144
|
+
chainLabel: chainLabel(config.chainId),
|
|
29145
|
+
type: "yield",
|
|
29146
|
+
governanceToken: addrLower,
|
|
29147
|
+
delegates,
|
|
29148
|
+
totalDelegates: data.governance?.currentDelegates ?? 0
|
|
29149
|
+
});
|
|
29150
|
+
return;
|
|
29151
|
+
}
|
|
29152
|
+
printHeader(`Delegates — ${formatAddress(address)} (${chainLabel(config.chainId)})`);
|
|
29153
|
+
if (data.governance) {
|
|
29154
|
+
console.log(`Active delegates: ${data.governance.currentDelegates} (${data.governance.totalDelegates} total)`);
|
|
29155
|
+
}
|
|
29156
|
+
console.log();
|
|
29157
|
+
printTable([
|
|
29158
|
+
{ header: "#", key: "rank", align: "right" },
|
|
29159
|
+
{ header: "Delegate", key: "delegate" },
|
|
29160
|
+
{ header: "Votes", key: "votes", align: "right" },
|
|
29161
|
+
{ header: "Holders", key: "holders", align: "right" },
|
|
29162
|
+
{ header: "Cast", key: "cast", align: "right" }
|
|
29163
|
+
], delegates.map((d) => ({
|
|
29164
|
+
rank: String(d.rank),
|
|
29165
|
+
delegate: formatAddress(d.address),
|
|
29166
|
+
votes: d.delegatedVotesHuman.toLocaleString("en-US", { maximumFractionDigits: 0 }),
|
|
29167
|
+
holders: String(d.representedHolders),
|
|
29168
|
+
cast: String(d.votesCast)
|
|
29169
|
+
})));
|
|
29170
|
+
}
|
|
29171
|
+
|
|
27698
29172
|
// src/index.ts
|
|
27699
29173
|
var HELP = `
|
|
27700
|
-
dtf — Reserve Protocol Index
|
|
29174
|
+
dtf — Reserve Protocol DTF CLI (Index + Yield)
|
|
27701
29175
|
|
|
27702
29176
|
Usage:
|
|
27703
29177
|
dtf <command> <address|symbol> [options]
|
|
@@ -27719,6 +29193,9 @@ Commands:
|
|
|
27719
29193
|
earn Vote-lock yield opportunities
|
|
27720
29194
|
revenue <address> | --all Revenue breakdown (single DTF or ecosystem)
|
|
27721
29195
|
rsr-burns RSR burn analytics + projections
|
|
29196
|
+
holders <address> Top token holders with balances
|
|
29197
|
+
delegates <address> Governance delegation graph
|
|
29198
|
+
query '<graphql>' Raw subgraph query (auto-detects index vs yield)
|
|
27722
29199
|
deploy Deploy a new DTF (--help for options)
|
|
27723
29200
|
forum Reserve governance forum (monthly top, search, topic detail)
|
|
27724
29201
|
cache-clear Clear local disk cache (~/.dtf/cache)
|
|
@@ -27734,6 +29211,7 @@ Command Options:
|
|
|
27734
29211
|
--account <address> Account address for staking command
|
|
27735
29212
|
--nonce <n> Rebalance nonce for history detail
|
|
27736
29213
|
--performance <period> Return over period (30d, 3m, 6m, 1y) for discover
|
|
29214
|
+
--subgraph <index|yield> Subgraph to query (auto-detected from entity names)
|
|
27737
29215
|
|
|
27738
29216
|
Address:
|
|
27739
29217
|
Use a 0x address or a known DTF symbol (case-insensitive).
|
|
@@ -27747,7 +29225,7 @@ Examples:
|
|
|
27747
29225
|
dtf discover All chains by default
|
|
27748
29226
|
dtf discover --chain 8453 Single chain
|
|
27749
29227
|
`;
|
|
27750
|
-
var NO_ADDRESS_COMMANDS = new Set(["discover", "earn", "cache-clear", "proposals", "rsr-burns", "revenue", "forum", "deploy"]);
|
|
29228
|
+
var NO_ADDRESS_COMMANDS = new Set(["discover", "earn", "cache-clear", "proposals", "rsr-burns", "revenue", "forum", "deploy", "query"]);
|
|
27751
29229
|
async function main() {
|
|
27752
29230
|
const args = process.argv.slice(2);
|
|
27753
29231
|
if (args.length === 0 || args[0] === "help" || args.includes("--help") && !args[0]?.match(/^[a-z]/)) {
|
|
@@ -27783,6 +29261,9 @@ async function main() {
|
|
|
27783
29261
|
if (!config.chainExplicit) {
|
|
27784
29262
|
config.chainId = resolved.chainId;
|
|
27785
29263
|
}
|
|
29264
|
+
config.dtfType = resolved.type;
|
|
29265
|
+
} else {
|
|
29266
|
+
config.dtfType = getRegistryType(address);
|
|
27786
29267
|
}
|
|
27787
29268
|
}
|
|
27788
29269
|
try {
|
|
@@ -27821,6 +29302,12 @@ async function main() {
|
|
|
27821
29302
|
case "rebalance-history":
|
|
27822
29303
|
await rebalanceHistoryCommand(resolvedAddress, config, rest);
|
|
27823
29304
|
break;
|
|
29305
|
+
case "holders":
|
|
29306
|
+
await holdersCommand(resolvedAddress, config);
|
|
29307
|
+
break;
|
|
29308
|
+
case "delegates":
|
|
29309
|
+
await delegatesCommand(resolvedAddress, config);
|
|
29310
|
+
break;
|
|
27824
29311
|
case "discover":
|
|
27825
29312
|
await discoverCommand(config);
|
|
27826
29313
|
break;
|
|
@@ -27840,6 +29327,9 @@ async function main() {
|
|
|
27840
29327
|
case "deploy":
|
|
27841
29328
|
await deployCommand(config, args.slice(1));
|
|
27842
29329
|
break;
|
|
29330
|
+
case "query":
|
|
29331
|
+
await queryCommand(config, address ? [address, ...rest] : rest);
|
|
29332
|
+
break;
|
|
27843
29333
|
case "forum":
|
|
27844
29334
|
await forumCommand(config, address ? [address, ...rest] : rest);
|
|
27845
29335
|
break;
|