Skip to content

Commit 424330e

Browse files
authored
track prediction markets' notional volume (#5764)
* track kalshi,polymarket, limitless notional volume * track probable, opinion,pcs-prediction, predict fun, myriad markets notional * track rain one notional * add more contracts for limitless * add pullhourly
1 parent 7d0d509 commit 424330e

File tree

10 files changed

+110
-35
lines changed

10 files changed

+110
-35
lines changed

dexs/kalshi.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,29 @@ async function fetch(_a: any, _b: any, options: FetchOptions) {
1515
),
1616
market_report_agg AS (
1717
SELECT
18-
SUM(CASE WHEN status = 'active' THEN open_interest ELSE 0 END) AS open_interest
18+
SUM(CASE WHEN status = 'active' THEN open_interest ELSE 0 END) AS open_interest,
19+
SUM(daily_volume) AS notional_volume
1920
FROM kalshi.market_report
2021
WHERE date = '${dateString}'
2122
)
2223
SELECT
2324
tr.cash_volume,
24-
mr.open_interest
25+
mr.open_interest,
26+
mr.notional_volume
2527
FROM trade_report_agg tr
2628
CROSS JOIN market_report_agg mr
2729
`
2830
const data: {
2931
cash_volume: string,
30-
open_interest: string
32+
open_interest: string,
33+
notional_volume: string,
3134
}[] = await queryDuneSql(options, query)
3235

3336
const dailyVolume = Number(data[0]?.cash_volume) || 0
3437
const openInterestAtEnd = Number(data[0]?.open_interest) || 0
38+
const dailyNotionalVolume = Number(data[0]?.notional_volume) || 0
3539

36-
return { dailyVolume, openInterestAtEnd }
40+
return { dailyVolume, openInterestAtEnd, dailyNotionalVolume }
3741
}
3842

3943
const adapter: SimpleAdapter = {

dexs/limitless-exchange/index.ts

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,20 @@ const contracts = {
1313
FEE_MODULE: "0x6d8a7d1898306ca129a74c296d14e55e20aae87d",
1414
NEG_RISK_FEE_MODULE: "0x73fc1b1395ba964fea8705bff7ef8ea5c23cc661",
1515

16+
CTF_EXCHANGE_V2: "0xf1de958f8641448a5ba78c01f434085385af096d",
17+
NEG_RISK_CTF_EXCHANGE_V2: "0x46e607d3f4a8494b0ab9b304d1463e2f4848891d",
18+
FEE_MODULE_V2: "0xEECD2Cf0FF29D712648fC328be4EE02FC7931c7A",
19+
NEG_RISK_FEE_MODULE_V2: "0x18B3E1192c01286050A0994Bc26f7226Ae4A483d",
20+
1621
// new main exchanges
17-
CTF_EXCHANGE_V2: "0x05c748e2f4dcde0ec9fa8ddc40de6b867f923fa5",
18-
NEG_RISK_CTF_EXCHANGE_V2: "0xe3e00ba3a9888d1de4834269f62ac008b4bb5c47",
19-
FEE_MODULE_V2: "0x5130c2c398F930c4f43B15635410047cBEa9D6EB",
20-
NEG_RISK_FEE_MODULE_V2: "0xfeb646D32a2A558359419a1C9c5dfb47fD92dADb",
22+
CTF_EXCHANGE_V3: "0x05c748e2f4dcde0ec9fa8ddc40de6b867f923fa5",
23+
NEG_RISK_CTF_EXCHANGE_V3: "0xe3e00ba3a9888d1de4834269f62ac008b4bb5c47",
24+
FEE_MODULE_V3: "0x5130c2c398F930c4f43B15635410047cBEa9D6EB",
25+
NEG_RISK_FEE_MODULE_V3: "0xfeb646D32a2A558359419a1C9c5dfb47fD92dADb",
2126

2227
WRAPPED_COLLATERAL_1: "0x5d6C6a4fEA600E0b1A3Ab3eF711060310E27886A",
2328
WRAPPED_COLLATERAL_2: "0x8f4fA186E00E376a9054968a03172cfa1c2EedfE",
29+
WRAPPED_COLLATERAL_3: "0x81140765fcf9D3a66CD9AA11cb972F9e07bc5deA",
2430

2531
CONDITIONAL_TOKENS: "0xC9c98965297Bc527861c898329Ee280632B76e18",
2632
FEE_RECIPIENT: "0x88eaf31f9fE392002e0E818527f8259af92287b1",
@@ -37,13 +43,16 @@ const abi = {
3743
async function fetch(options: FetchOptions) {
3844
const dailyVolume = options.createBalances();
3945
const dailyFees = options.createBalances();
46+
const dailyNotionalVolume = options.createBalances();
4047
const fpmmMarkets: any[] = [];
4148

4249
const exchangeTargets = [
4350
contracts.CTF_EXCHANGE,
4451
contracts.NEG_RISK_CTF_EXCHANGE,
4552
contracts.CTF_EXCHANGE_V2,
4653
contracts.NEG_RISK_CTF_EXCHANGE_V2,
54+
contracts.CTF_EXCHANGE_V3,
55+
contracts.NEG_RISK_CTF_EXCHANGE_V3,
4756
];
4857

4958
const marketCreationLogs = await options.getLogs({
@@ -70,11 +79,13 @@ async function fetch(options: FetchOptions) {
7079
const collateralToken = fpmmMarketMap[log.address.toLowerCase()]
7180
if (!collateralToken) return;
7281
dailyVolume.addToken(collateralToken, log.args.investmentAmount);
82+
dailyNotionalVolume.addToken(collateralToken, log.args.outcomeTokensBought);
7383
})
7484
sellLogs.forEach(log => {
7585
const collateralToken = fpmmMarketMap[log.address.toLowerCase()]
7686
if (!collateralToken) return;
7787
dailyVolume.addToken(collateralToken, log.args.returnAmount);
88+
dailyNotionalVolume.addToken(collateralToken, log.args.outcomeTokensSold);
7889
})
7990

8091
const orderMatchedLogs = await options.getLogs({
@@ -86,13 +97,15 @@ async function fetch(options: FetchOptions) {
8697
const { makerAssetId, makerAmountFilled, takerAmountFilled } = order;
8798
const makerIdStr = makerAssetId?.toString?.() ?? String(makerAssetId);
8899
const tradeVolume = makerIdStr === '0' ? makerAmountFilled : takerAmountFilled;
100+
const notionalTradeVolume = makerIdStr === '0' ? takerAmountFilled : makerAmountFilled;
89101
dailyVolume.addToken(ADDRESSES.base.USDC, tradeVolume);
102+
dailyNotionalVolume.addToken(ADDRESSES.base.USDC, notionalTradeVolume);
90103
});
91104

92105
await addTokensReceived({
93106
options,
94107
balances: dailyFees,
95-
fromAdddesses: [contracts.CONDITIONAL_TOKENS, contracts.FEE_MODULE, contracts.FEE_MODULE_V2, contracts.WRAPPED_COLLATERAL_1, contracts.WRAPPED_COLLATERAL_2, contracts.NEG_RISK_FEE_MODULE, contracts.NEG_RISK_FEE_MODULE_V2],
108+
fromAdddesses: [contracts.CONDITIONAL_TOKENS, contracts.FEE_MODULE, contracts.FEE_MODULE_V2, contracts.FEE_MODULE_V3, contracts.WRAPPED_COLLATERAL_1,contracts.WRAPPED_COLLATERAL_2, contracts.WRAPPED_COLLATERAL_3, contracts.NEG_RISK_FEE_MODULE, contracts.NEG_RISK_FEE_MODULE_V2, contracts.NEG_RISK_FEE_MODULE_V3],
96109
target: contracts.FEE_RECIPIENT,
97110
token: ADDRESSES.base.USDC
98111
});
@@ -103,6 +116,7 @@ async function fetch(options: FetchOptions) {
103116
dailyRevenue: dailyFees,
104117
dailyProtocolRevenue: dailyFees,
105118
dailyHoldersRevenue: 0,
119+
dailyNotionalVolume,
106120
};
107121
}
108122

dexs/opinion/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ async function fetch(options: FetchOptions): Promise<FetchResult> {
6464
const dailyVolume = options.createBalances()
6565
const tradeFees = options.createBalances()
6666
const rebateFees = options.createBalances()
67+
const dailyNotionalVolume = options.createBalances()
6768

6869
const orderFilledLogs = await options.getLogs({
6970
eventAbi: ORDER_FILLED_EVENT,
@@ -86,7 +87,9 @@ async function fetch(options: FetchOptions): Promise<FetchResult> {
8687
}
8788

8889
const tradeVolume = Number(order.makerAssetId == 0 ? order.makerAmountFilled : order.takerAmountFilled) / 1e18
90+
const notionalVolume = Number(order.makerAssetId == 0 ? order.takerAmountFilled : order.makerAmountFilled) / 1e18
8991
dailyVolume.addUSDValue(Number(tradeVolume) / 2)
92+
dailyNotionalVolume.addUSDValue(notionalVolume / 2)
9093
})
9194

9295
rebateEarnedLogs.forEach((log: any) => {
@@ -102,6 +105,7 @@ async function fetch(options: FetchOptions): Promise<FetchResult> {
102105
dailyFees,
103106
dailyRevenue: dailyFees,
104107
dailyProtocolRevenue: dailyFees,
108+
dailyNotionalVolume,
105109
}
106110
}
107111

dexs/pancakeswap-prediction/index.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ const EVENT_ABI = {
1212
async function fetch(options: FetchOptions) {
1313
const dailyVolume = options.createBalances();
1414
const dailyFees = options.createBalances();
15+
const dailyNotionalVolume = options.createBalances();
16+
17+
const epochData: Map<number, { bullAmount: bigint; bearAmount: bigint }> = new Map();
1518

1619
const bullLogs = await options.getLogs({
1720
target: PCS_BNB_PREDICTION_CONTRACT,
@@ -20,6 +23,10 @@ async function fetch(options: FetchOptions) {
2023

2124
bullLogs.forEach(bet => {
2225
dailyVolume.add(ADDRESSES.bsc.WBNB, bet.amount);
26+
const epoch = bet.epoch;
27+
const data = epochData.get(epoch) || { bullAmount: 0n, bearAmount: 0n };
28+
data.bullAmount += BigInt(bet.amount);
29+
epochData.set(epoch, data);
2330
});
2431

2532
const bearLogs = await options.getLogs({
@@ -29,6 +36,10 @@ async function fetch(options: FetchOptions) {
2936

3037
bearLogs.forEach(bet => {
3138
dailyVolume.add(ADDRESSES.bsc.WBNB, bet.amount);
39+
const epoch = bet.epoch;
40+
const data = epochData.get(epoch) || { bullAmount: 0n, bearAmount: 0n };
41+
data.bearAmount += BigInt(bet.amount);
42+
epochData.set(epoch, data);
3243
});
3344

3445
const rewardLogs = await options.getLogs({
@@ -40,11 +51,20 @@ async function fetch(options: FetchOptions) {
4051
dailyFees.add(ADDRESSES.bsc.WBNB, reward.treasuryAmount);
4152
});
4253

43-
return {
54+
epochData.forEach(({ bullAmount, bearAmount }) => {
55+
if (bullAmount > 0n && bearAmount > 0n) {
56+
const total = bullAmount + bearAmount;
57+
const notional = (total * (bullAmount * bullAmount + bearAmount * bearAmount)) / (bullAmount * bearAmount);
58+
dailyNotionalVolume.add(ADDRESSES.bsc.WBNB, notional);
59+
}
60+
});
61+
62+
return {
4463
dailyVolume,
4564
dailyFees,
4665
dailyRevenue: dailyFees,
47-
dailyProtocolRevenue:0,
66+
dailyNotionalVolume,
67+
dailyProtocolRevenue: 0,
4868
dailyHoldersRevenue: dailyFees,
4969
};
5070
}

dexs/polymarket/index.ts

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,18 @@ const fetch = async (_a: any, _b: any, options: FetchOptions) => {
4949
select * from market_data
5050
)
5151
SELECT
52-
SUM(volume_usd) as total_volume_usd
52+
SUM(volume_usd) as total_volume_usd,
53+
SUM(notional_volume) as total_notional_volume
5354
FROM (
5455
SELECT
55-
SUM(CASE
56+
SUM(CASE
5657
WHEN makerAssetId = 0 THEN makerAmountFilled
57-
WHEN takerAssetId = 0 THEN takerAmountFilled
58-
END) / 1e6 as volume_usd
58+
WHEN takerAssetId = 0 THEN takerAmountFilled
59+
END) / 1e6 as volume_usd,
60+
SUM(CASE
61+
WHEN makerAssetId = 0 THEN takerAmountFilled
62+
WHEN takerAssetId = 0 THEN makerAmountFilled
63+
END) / 1e6 as notional_volume
5964
FROM polymarket_polygon.NegRiskCtfExchange_evt_OrderFilled b
6065
where b.evt_block_number > 50505492
6166
and evt_block_time >= from_unixtime(${options.startTimestamp})
@@ -64,10 +69,14 @@ const fetch = async (_a: any, _b: any, options: FetchOptions) => {
6469
UNION ALL
6570
6671
SELECT
67-
SUM(CASE
72+
SUM(CASE
6873
WHEN makerAssetId = 0 THEN makerAmountFilled
69-
WHEN takerAssetId = 0 THEN takerAmountFilled
70-
END) / 1e6 as volume_usd
74+
WHEN takerAssetId = 0 THEN takerAmountFilled
75+
END) / 1e6 as volume_usd,
76+
SUM(CASE
77+
WHEN makerAssetId = 0 THEN takerAmountFilled
78+
WHEN takerAssetId = 0 THEN makerAmountFilled
79+
END) / 1e6 as notional_volume
7180
FROM polymarket_polygon.CTFExchange_evt_OrderFilled a
7281
where a.evt_block_number > 33605403
7382
and evt_block_time >= from_unixtime(${options.startTimestamp})
@@ -76,7 +85,8 @@ const fetch = async (_a: any, _b: any, options: FetchOptions) => {
7685
UNION ALL
7786
7887
select
79-
bytearray_to_uint256(substr(pl.DATA, 1, 32)) / 1e6 as volume_usd
88+
bytearray_to_uint256(substr(pl.DATA, 1, 32)) / 1e6 as volume_usd,
89+
bytearray_to_uint256(substr(pl.DATA, 65, 96)) / 1e6 as notional_volume
8090
from
8191
polygon.logs pl
8292
left join polymarket_market_data md on pl.contract_address = md.market_maker_address
@@ -97,12 +107,14 @@ const fetch = async (_a: any, _b: any, options: FetchOptions) => {
97107
options.api.log(data);
98108

99109
const dailyVolume = options.createBalances();
110+
const dailyNotionalVolume = options.createBalances();
100111

101112
// Polymarket emits two OrderFilled events per trade (maker + taker), so summing them directly double-counts volume. Dividing by 2 converts this into true one-sided volume. This also normalizes swaps and merge/split fills, where maker and taker amounts can differ but still represent the same underlying trade, preventing inflated totals
102113

103114
dailyVolume.addUSDValue(data[0].total_volume_usd / 2);
115+
dailyNotionalVolume.addUSDValue(data[0].total_notional_volume/2);
104116

105-
return { dailyVolume }
117+
return { dailyVolume, dailyNotionalVolume }
106118
}
107119

108120
const adapters: SimpleAdapter = {

dexs/predict-fun/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,17 @@ const EXCHANGE_CONTRACT_ADDRESSES = [
1212
const USDT_ADDRESS = "0x55d398326f99059fF775485246999027B3197955";
1313

1414
const fetch = async (options: FetchOptions) => {
15-
const { dailyVolume } = await getPolymarketVolume({ options, exchanges: EXCHANGE_CONTRACT_ADDRESSES, currency: USDT_ADDRESS });
15+
const { dailyVolume, dailyNotionalVolume } = await getPolymarketVolume({ options, exchanges: EXCHANGE_CONTRACT_ADDRESSES, currency: USDT_ADDRESS });
1616

1717
return {
1818
dailyVolume,
19+
dailyNotionalVolume,
1920
};
2021
};
2122

2223
const adapter: SimpleAdapter = {
2324
version: 2,
25+
pullHourly: true,
2426
adapter: {
2527
[CHAIN.BSC]: {
2628
fetch,

dexs/probable.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,18 @@ const EXCHANGE_CONTRACT_ADDRESS = "0xf99f5367ce708c66f0860b77b4331301a5597c86";
66
const USDT_ADDRESS = "0x55d398326f99059fF775485246999027B3197955";
77

88
const fetch = async (options: FetchOptions) => {
9-
const { dailyVolume } = await getPolymarketVolume({ options, exchanges: [EXCHANGE_CONTRACT_ADDRESS], currency: USDT_ADDRESS });
9+
const { dailyVolume, dailyNotionalVolume } = await getPolymarketVolume({ options, exchanges: [EXCHANGE_CONTRACT_ADDRESS], currency: USDT_ADDRESS });
1010

1111
return {
1212
dailyVolume,
1313
dailyFees: 0, // no fees
14+
dailyNotionalVolume
1415
};
1516
};
1617

1718
const adapter: SimpleAdapter = {
1819
version: 2,
20+
pullHourly: true,
1921
adapter: {
2022
[CHAIN.BSC]: {
2123
fetch,

dexs/rain-one/index.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const poolTokenSetEvent =
1212

1313
const fetch = async (options: FetchOptions) => {
1414
const dailyVolume = options.createBalances();
15+
const dailyNotionalVolume = options.createBalances();
1516

1617
const poolCreationLogs = await options.getLogs({
1718
target: rainFactory,
@@ -58,7 +59,17 @@ const fetch = async (options: FetchOptions) => {
5859
}
5960
})
6061

61-
return { dailyVolume, }
62+
enterOptionLogs.forEach((log) => {
63+
const pool = log.address.toLowerCase();
64+
const tokenInfo = poolTokenMap[pool] ?? {
65+
token: usdt,
66+
decimals: 6,
67+
};
68+
if(!tokenInfo?.token) return;
69+
dailyVolume.addToken(tokenInfo.token, log.args.baseAmount);
70+
dailyNotionalVolume.addToken(tokenInfo.token, log.args.optionAmount);
71+
});
72+
return { dailyVolume, dailyNotionalVolume };
6273
};
6374

6475
const methodology = {

fees/myriadmarkets/index.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { FetchOptions, SimpleAdapter } from "../../adapters/types";
22
import { CHAIN } from "../../helpers/chains";
33

4-
const MARKETS = {
4+
const MARKETS:any = {
55
[CHAIN.ABSTRACT]: '0x3e0F5F8F5Fb043aBFA475C0308417Bf72c463289',
66
[CHAIN.LINEA]: '0x39e66ee6b2ddaf4defded3038e0162180dbef340',
77
[CHAIN.BSC]: '0x39e66ee6b2ddaf4defded3038e0162180dbef340',
@@ -19,24 +19,27 @@ async function fetch({ createBalances, chain, api, getLogs }: FetchOptions) {
1919
const dailyFees = createBalances();
2020
const dailySupplySideRevenue = createBalances();
2121
const dailyRevenue = createBalances();
22+
const dailyNotionalVolume = createBalances();
2223

2324
const markets = await api.call({ abi: 'uint256[]:getMarkets', target: market });
2425
const marketData = await api.multiCall({ target: market, abi: abi.getMarketAltData, calls: markets })
2526
const marketFees = (await api.multiCall({ target: market, abi: abi.getMarketFees, calls: markets }))
2627
const marketMapping: any = {}
27-
markets.forEach((val, idx) => marketMapping[val] = {
28+
markets.forEach((val:any, idx:any) => marketMapping[val] = {
2829
token: marketData[idx].token,
2930
fees: marketFees[idx]
3031
})
3132

3233
marketFees.forEach(i => {
33-
i.buyFees = i.buyFees.map(j => Number(j) / 1e18)
34+
i.buyFees = i.buyFees.map((j:any) => Number(j) / 1e18)
3435
})
3536
const tradeLogs = await getLogs({ target: market, eventAbi: abi.MarketActionTx, });
3637

37-
tradeLogs.forEach(({ action, marketId, value }) => {
38+
tradeLogs.forEach(({ action, marketId, value, shares }) => {
3839
value = Number(value)
3940
action = Number(action)
41+
shares = Number(shares)
42+
4043
const { fees, token } = marketMapping[marketId]
4144
const isBuy = action === 0
4245
const feeKey = isBuy ? 'buyFees' : 'sellFees'
@@ -47,6 +50,7 @@ async function fetch({ createBalances, chain, api, getLogs }: FetchOptions) {
4750
case 0: // buy
4851
case 1: // sell
4952
dailyVolume.add(token, value);
53+
dailyNotionalVolume.add(token, shares);
5054
dailyFees.add(token, value * totalFee, isBuy ? 'BuyFee' : 'SellFee')
5155
dailySupplySideRevenue.add(token, value * distributorFee, 'DistributorFee')
5256
dailySupplySideRevenue.add(token, value * fee, 'LPFee')
@@ -58,9 +62,10 @@ async function fetch({ createBalances, chain, api, getLogs }: FetchOptions) {
5862

5963
return {
6064
dailyVolume,
65+
dailyNotionalVolume,
6166
dailyFees,
6267
dailyRevenue,
63-
dailyProtocolRevenue: dailyRevenue.clone(),
68+
dailyProtocolRevenue: dailyRevenue,
6469
dailyHoldersRevenue: 0,
6570
dailySupplySideRevenue
6671
};

0 commit comments

Comments
 (0)