Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
22216ca
feat: add treasury multi-provider architecture
LeonardoVieira1630 Dec 17, 2025
76589f3
refactor: update environment configuration for treasury
LeonardoVieira1630 Dec 17, 2025
2f6e0b9
refactor: migrate dune service to treasury providers
LeonardoVieira1630 Dec 17, 2025
0283395
refactor: integrate treasury provider factory in API
LeonardoVieira1630 Dec 17, 2025
27c96a9
chore: update dependencies for treasury support
LeonardoVieira1630 Dec 17, 2025
bd68c09
refactor: createTreasuryProvider
LeonardoVieira1630 Dec 18, 2025
41b7c0c
feat: treasury interfaces and types
LeonardoVieira1630 Dec 18, 2025
f3e7c46
refactor: dao-config to remove the supportsLiquidTreasuryCall
LeonardoVieira1630 Dec 18, 2025
f24d6e9
refactor: delete old treasury-related files
LeonardoVieira1630 Dec 18, 2025
5a59b24
refactor: remove old imports
LeonardoVieira1630 Dec 19, 2025
726062a
refactor: types.ts
LeonardoVieira1630 Dec 19, 2025
2509205
refactor: remove old treasury endpoint
LeonardoVieira1630 Dec 19, 2025
733f340
feat: treasury repository
LeonardoVieira1630 Dec 19, 2025
7257545
refactor: createTreasuryProvider to return the service
LeonardoVieira1630 Dec 19, 2025
131d2a0
refactor: imports on the /treasury.index.ts
LeonardoVieira1630 Dec 19, 2025
1604cb7
feat: treasury zod schemas
LeonardoVieira1630 Dec 19, 2025
902be53
feat: fowardFill functions
LeonardoVieira1630 Dec 19, 2025
596f40d
refactor: remove daoId dependecy
LeonardoVieira1630 Dec 19, 2025
a368702
feat: treasury controller
LeonardoVieira1630 Dec 19, 2025
2bb1f04
refactor: removing treasury types em router func
LeonardoVieira1630 Dec 19, 2025
b3115c0
feat: time related funcs to the shared file
LeonardoVieira1630 Dec 19, 2025
d655049
feat: add cutoffTimestamp to the fetch treasury and providers
LeonardoVieira1630 Dec 19, 2025
bec59ed
feat: move createDailyTimelineFromData to the foward-fill file
LeonardoVieira1630 Dec 19, 2025
d934307
feat: treasury service file
LeonardoVieira1630 Dec 19, 2025
ca9659f
refactor: useTreasury function
LeonardoVieira1630 Dec 19, 2025
96c956b
feat: getLastTokenQuantityBeforeDate
LeonardoVieira1630 Dec 22, 2025
f94c70d
refactor: treasury endpoint usage on the frontend
LeonardoVieira1630 Dec 22, 2025
1b3bb24
refactor: useDaoTreasuryStats to use 7d instead of 1
LeonardoVieira1630 Dec 22, 2025
ab5af3a
feat: createTokenPriceProvider
LeonardoVieira1630 Dec 22, 2025
77e3d6f
refactor: useTreasury to follow the days standard
LeonardoVieira1630 Dec 22, 2025
f19a9aa
refactor: unnecessary Number(days.split("d")[0])
LeonardoVieira1630 Dec 22, 2025
f825c22
refactor: decouple treasury endpoint creation and provider
LeonardoVieira1630 Dec 22, 2025
b07eb19
refactor: decouple env and treasury factory
LeonardoVieira1630 Dec 22, 2025
6b943f8
refactor: move const for other file
LeonardoVieira1630 Dec 22, 2025
97df519
refactor: outdated interface
LeonardoVieira1630 Dec 22, 2025
f4d4da1
refactor: function name
LeonardoVieira1630 Dec 22, 2025
670fff4
refactor: improve comments
LeonardoVieira1630 Dec 22, 2025
08d7b1f
feat: add getLastTokenQuantityBeforeDate in the getTokenTreasury func…
LeonardoVieira1630 Dec 22, 2025
a37a26f
refactor: remove old db query
LeonardoVieira1630 Dec 22, 2025
e689503
refactor: timestamp to be number not bigint
LeonardoVieira1630 Dec 23, 2025
aa23384
refactor: remove duplicated interface TreasuryResponse
LeonardoVieira1630 Dec 23, 2025
7d61c65
refactor: move file dir
LeonardoVieira1630 Dec 23, 2025
e7dbe3c
refactor: inject repo on service
LeonardoVieira1630 Dec 23, 2025
ed85194
refactor: createDailyTimelineFromData to receive a vec
LeonardoVieira1630 Dec 23, 2025
b0e4b90
refactor: coingeckoPriceProvider class
LeonardoVieira1630 Dec 23, 2025
2126cc2
refactor: function name
LeonardoVieira1630 Dec 23, 2025
025c63b
refactor: useTreasury
LeonardoVieira1630 Dec 23, 2025
899f51d
Merge branch 'dev' into refactor/DEV-234_create_treasury_endpoint
LeonardoVieira1630 Jan 5, 2026
56d350c
Merge branch 'dev' into refactor/DEV-234_create_treasury_endpoint
pikonha Jan 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 87 additions & 6 deletions apps/api-gateway/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,18 @@ type Query {
tokenPrices(where: tokenPriceFilter, orderBy: String, orderDirection: String, before: String, after: String, limit: Int): tokenPricePage!
_meta: Meta

"""Get total assets"""
totalAssets(days: queryInput_totalAssets_days = _7d): [query_totalAssets_items]
"""
Get historical Liquid Treasury (treasury without DAO tokens) from external providers (DefiLlama/Dune)
"""
getLiquidTreasury(days: queryInput_getLiquidTreasury_days = _365d, order: queryInput_getLiquidTreasury_order = asc): getLiquidTreasury_200_response

"""
Get historical DAO Token Treasury value (governance token quantity × token price)
"""
getDaoTokenTreasury(days: queryInput_getDaoTokenTreasury_days = _365d, order: queryInput_getDaoTokenTreasury_order = asc): getDaoTokenTreasury_200_response

"""Get historical Total Treasury (liquid treasury + DAO token treasury)"""
getTotalTreasury(days: queryInput_getTotalTreasury_days = _365d, order: queryInput_getTotalTreasury_order = asc): getTotalTreasury_200_response

"""Get historical market data for a specific token"""
historicalTokenData(skip: NonNegativeInt, limit: Float = 365): [query_historicalTokenData_items]
Expand Down Expand Up @@ -1330,19 +1340,90 @@ input tokenPriceFilter {
timestamp_lte: BigInt
}

type query_totalAssets_items {
totalAssets: String!
date: String!
type getLiquidTreasury_200_response {
items: [query_getLiquidTreasury_items_items]!

"""Total number of items"""
totalCount: Float!
}

type query_getLiquidTreasury_items_items {
"""Treasury value in USD"""
value: Float!

"""Unix timestamp in milliseconds"""
date: Float!
}

enum queryInput_getLiquidTreasury_days {
_7d
_30d
_90d
_180d
_365d
}

enum queryInput_getLiquidTreasury_order {
asc
desc
}

type getDaoTokenTreasury_200_response {
items: [query_getDaoTokenTreasury_items_items]!

"""Total number of items"""
totalCount: Float!
}

type query_getDaoTokenTreasury_items_items {
"""Treasury value in USD"""
value: Float!

"""Unix timestamp in milliseconds"""
date: Float!
}

enum queryInput_getDaoTokenTreasury_days {
_7d
_30d
_90d
_180d
_365d
}

enum queryInput_getDaoTokenTreasury_order {
asc
desc
}

enum queryInput_totalAssets_days {
type getTotalTreasury_200_response {
items: [query_getTotalTreasury_items_items]!

"""Total number of items"""
totalCount: Float!
}

type query_getTotalTreasury_items_items {
"""Treasury value in USD"""
value: Float!

"""Unix timestamp in milliseconds"""
date: Float!
}

enum queryInput_getTotalTreasury_days {
_7d
_30d
_90d
_180d
_365d
}

enum queryInput_getTotalTreasury_order {
asc
desc
}

type query_historicalTokenData_items {
price: String!
timestamp: Float!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { mockedAttackCostBarData } from "@/shared/constants/mocked-data/mocked-a
import {
useDaoTokenHistoricalData,
useTopTokenHolderNonDao,
useTreasuryAssetNonDaoToken,
useTreasury,
useVetoCouncilVotingPower,
} from "@/features/attack-profitability/hooks";
import daoConfigByDaoId from "@/shared/dao-config";
Expand Down Expand Up @@ -71,10 +71,8 @@ export const AttackCostBarChart = ({
const selectedDaoId = daoId.toUpperCase() as DaoIdEnum;
const timeInterval = TimeInterval.NINETY_DAYS;

const liquidTreasury = useTreasuryAssetNonDaoToken(
selectedDaoId,
timeInterval,
);
const { data: liquidTreasuryData, loading: liquidTreasuryLoading } =
useTreasury(selectedDaoId, "liquid", TimeInterval.SEVEN_DAYS);
const delegatedSupply = useDelegatedSupply(selectedDaoId, timeInterval);
const activeSupply = useActiveSupply(selectedDaoId, timeInterval);
const averageTurnout = useAverageTurnout(selectedDaoId, timeInterval);
Expand Down Expand Up @@ -104,7 +102,7 @@ export const AttackCostBarChart = ({
const { isMobile } = useScreenSize();

const isLoading =
liquidTreasury.loading ||
liquidTreasuryLoading ||
delegatedSupply.isLoading ||
activeSupply.isLoading ||
averageTurnout.isLoading ||
Expand Down Expand Up @@ -152,10 +150,10 @@ export const AttackCostBarChart = ({
id: "liquidTreasury",
name: "Liquid Treasury",
type: BarChartEnum.REGULAR,
value: Number(liquidTreasury.data?.[0]?.totalAssets || 0),
value: Number(liquidTreasuryData?.[0]?.value || 0),
customColor: "#EC762EFF",
displayValue:
Number(liquidTreasury.data?.[0]?.totalAssets || 0) > 10000
Number(liquidTreasuryData?.[0]?.value || 0) > 10000
? undefined
: "<$10,000",
},
Expand Down Expand Up @@ -226,7 +224,7 @@ export const AttackCostBarChart = ({
mocked,
daoTokenPriceHistoricalData,
valueMode,
liquidTreasury.data,
liquidTreasuryData,
delegatedSupply.data?.currentDelegatedSupply,
activeSupply.data?.activeSupply,
averageTurnout.data?.currentAverageTurnout,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,14 @@ import { ResearchPendingChartBlur } from "@/shared/components/charts/ResearchPen
import { AttackProfitabilityCustomTooltip } from "@/features/attack-profitability/components";
import {
useDaoTokenHistoricalData,
useTreasuryAssetNonDaoToken,
useTreasury,
} from "@/features/attack-profitability/hooks";
import {
cn,
formatNumberUserReadable,
timestampToReadableDate,
} from "@/shared/utils";
import {
normalizeDataset,
normalizeDatasetTreasuryNonDaoToken,
normalizeDatasetAllTreasury,
} from "@/features/attack-profitability/utils";
import { normalizeDataset } from "@/features/attack-profitability/utils";
import daoConfigByDaoId from "@/shared/dao-config";
import { AnticaptureWatermark } from "@/shared/components/icons/AnticaptureWatermark";
import { Data } from "react-csv/lib/core";
Expand All @@ -62,14 +58,20 @@ export const MultilineChartAttackProfitability = ({
const { data: daoData } = useDaoData(daoEnum);
const daoConfig = daoConfigByDaoId[daoEnum];

const { data: treasuryAssetNonDAOToken = [] } = useTreasuryAssetNonDaoToken(
const { data: liquidTreasuryData } = useTreasury(
daoEnum,
days,
"liquid",
days as TimeInterval,
);
const { data: totalTreasuryData } = useTreasury(
daoEnum,
"total",
days as TimeInterval,
);

const { data: daoTokenPriceHistoricalData } = useDaoTokenHistoricalData({
daoId: daoEnum,
limit: Number(days.split("d")[0]) - 7,
limit: Number(days.split("d")[0]),
});

const { data: timeSeriesData } = useTimeSeriesData(
Expand Down Expand Up @@ -108,9 +110,7 @@ export const MultilineChartAttackProfitability = ({

const chartData = useMemo(() => {
let delegatedSupplyChart: DaoMetricsDayBucket[] = [];
let treasurySupplyChart: DaoMetricsDayBucket[] = [];
if (timeSeriesData) {
treasurySupplyChart = timeSeriesData[MetricTypesEnum.TREASURY];
delegatedSupplyChart = timeSeriesData[MetricTypesEnum.DELEGATED_SUPPLY];
}

Expand All @@ -119,17 +119,14 @@ export const MultilineChartAttackProfitability = ({
datasets = mockedAttackProfitabilityDatasets;
} else {
datasets = {
treasuryNonDAO: normalizeDatasetTreasuryNonDaoToken(
treasuryAssetNonDAOToken,
"treasuryNonDAO",
).reverse(),
all: normalizeDatasetAllTreasury(
daoTokenPriceHistoricalData,
"all",
treasuryAssetNonDAOToken,
treasurySupplyChart,
daoConfig.decimals,
),
treasuryNonDAO: liquidTreasuryData.map((item) => ({
date: item.date,
treasuryNonDAO: item.value,
})),
all: totalTreasuryData.map((item) => ({
date: item.date,
all: item.value,
})),
quorum: daoConfig?.attackProfitability?.dynamicQuorum?.percentage
? normalizeDataset(
daoTokenPriceHistoricalData,
Expand Down Expand Up @@ -195,7 +192,8 @@ export const MultilineChartAttackProfitability = ({
mocked,
quorumValue,
daoTokenPriceHistoricalData,
treasuryAssetNonDAOToken,
liquidTreasuryData,
totalTreasuryData,
timeSeriesData,
daoConfig?.attackProfitability?.dynamicQuorum?.percentage,
daoConfig.decimals,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export * from "@/features/attack-profitability/hooks/useVetoCouncilVotingPower";
export * from "@/features/attack-profitability/hooks/useDaoTokenHistoricalData";
export * from "@/features/attack-profitability/hooks/useTopTokenHolderNonDao";
export * from "@/features/attack-profitability/hooks/useTreasuryAssetNonDaoToken";
export * from "@/features/attack-profitability/hooks/useTreasury";
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import useSWR from "swr";
import axios from "axios";
import { DaoIdEnum } from "@/shared/types/daos";
import { TimeInterval } from "@/shared/types/enums/TimeInterval";
import { BACKEND_ENDPOINT } from "@/shared/utils/server-utils";

export type TreasuryType = "liquid" | "dao-token" | "total";

export interface TreasuryDataPoint {
value: number;
date: number;
}

export interface TreasuryResponse {
items: TreasuryDataPoint[];
totalCount: number;
}

const QUERY_NAME_MAP: Record<TreasuryType, string> = {
liquid: "getLiquidTreasury",
"dao-token": "getDaoTokenTreasury",
total: "getTotalTreasury",
};

const fetchTreasury = async ({
daoId,
type = "total",
days = TimeInterval.ONE_YEAR,
order = "asc",
}: {
daoId: DaoIdEnum;
type?: TreasuryType;
days?: TimeInterval;
order?: "asc" | "desc";
}): Promise<TreasuryResponse> => {
const queryName = QUERY_NAME_MAP[type];
const daysParam = `_${days}`;

const query = `query GetTreasury {
${queryName}(days: ${daysParam}, order: ${order}) {
items {
date
value
}
totalCount
}
}`;

const response: {
data: { data: { [key: string]: TreasuryResponse } };
} = await axios.post(
`${BACKEND_ENDPOINT}`,
{ query },
{ headers: { "anticapture-dao-id": daoId } },
);

return response.data.data[queryName];
};

export const useTreasury = (
daoId: DaoIdEnum,
type: TreasuryType = "total",
days: TimeInterval = TimeInterval.ONE_YEAR,
order: "asc" | "desc" = "asc",
) => {
const { data, error, isValidating } = useSWR<TreasuryResponse>(
["treasury", daoId, type, days, order],
() => fetchTreasury({ daoId, type, days, order }),
{
revalidateOnFocus: false,
shouldRetryOnError: false,
},
);

return {
data: data?.items ?? [],
totalCount: data?.totalCount ?? 0,
loading: isValidating,
error,
};
};
Loading