From 7ea59dd73185d03d7e9982dbab782a609a8282ae Mon Sep 17 00:00:00 2001 From: Tom Robiquet Date: Fri, 2 Jun 2023 18:29:48 +0300 Subject: [PATCH 01/40] fetch asset trades and redeems, group by account --- pages/leaderboard.tsx | 131 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 pages/leaderboard.tsx diff --git a/pages/leaderboard.tsx b/pages/leaderboard.tsx new file mode 100644 index 000000000..e16f2fde6 --- /dev/null +++ b/pages/leaderboard.tsx @@ -0,0 +1,131 @@ +import { GraphQLClient } from "graphql-request"; +import { endpointOptions, graphQlEndpoint } from "lib/constants"; +import { NextPage } from "next"; +import { + AssetId, + getMarketIdOf, + IOMarketOutcomeAssetId, + mainnet, + mainnetIndexer, + parseAssetId, + RpcContext, + Sdk, + ZeitgeistIpfs, +} from "@zeitgeistpm/sdk-next"; +import { create, mainnetRpc } from "@zeitgeistpm/sdk-next"; +import Decimal from "decimal.js"; + +type Trade = { + marketId: number; + // baseAsset: AssetId; + amountIn: Decimal; + amountOut: Decimal; + assetIn: AssetId; + assetOut: AssetId; + type: "trade" | "redeem"; +}; + +type Traders = { + [key: string]: Trade[]; +}; + +export async function getStaticProps() { + const client = new GraphQLClient(graphQlEndpoint); + // const sdk= await create(mainnet()); + const sdk = await create({ + provider: endpointOptions.map((e) => e.value), + indexer: graphQlEndpoint, + storage: ZeitgeistIpfs(), + }); + + const { historicalSwaps } = await sdk.indexer.historicalSwaps(); + console.log(historicalSwaps); + + const tradersWithSwaps = historicalSwaps.reduce( + (traders, swap, index) => { + const trades = traders[swap.accountId]; + + const assetInId = parseAssetId(swap.assetIn).unwrap(); + const assetOutId = parseAssetId(swap.assetOut).unwrap(); + + let marketId: number | undefined; + let baseAsset: AssetId | undefined; + if (IOMarketOutcomeAssetId.is(assetInId)) { + marketId = getMarketIdOf(assetInId); + baseAsset = assetOutId; + } else if (IOMarketOutcomeAssetId.is(assetOutId)) { + marketId = getMarketIdOf(assetOutId); + baseAsset = assetInId; + } + + const trade: Trade = { + marketId, + // baseAsset: baseAsset, + assetIn: assetInId, + assetOut: assetOutId, + amountIn: new Decimal(swap.assetAmountIn), + amountOut: new Decimal(swap.assetAmountOut), + type: "trade", + }; + + if (trades) { + trades.push(trade); + + traders[swap.accountId] = trades; + } else { + traders[swap.accountId] = [trade]; + } + + return traders; + }, + {}, + ); + + console.log(tradersWithSwaps); + const { historicalAccountBalances } = + await sdk.indexer.historicalAccountBalances({ + where: { event_contains: "TokensRedeemed" }, + }); + + console.log(historicalAccountBalances); + historicalAccountBalances.forEach((redeem) => { + const trades = tradersWithSwaps[redeem.accountId]; + + const assetInId = parseAssetId(redeem.assetId).unwrap(); + + const marketId = IOMarketOutcomeAssetId.is(assetInId) + ? getMarketIdOf(assetInId) + : undefined; + const redeemTrade: Trade = { + marketId, + // baseAsset: baseAsset, + assetIn: assetInId, + assetOut: { Ztg: null }, + amountIn: new Decimal(redeem.dBalance).abs(), + amountOut: new Decimal(redeem.dBalance).abs(), + type: "redeem", + }; + + trades.push(redeemTrade); + + tradersWithSwaps[redeem.accountId] = trades; + }); + + console.log(tradersWithSwaps); + + const rankings = []; + return { + props: { + rankings, + revalidate: 10 * 60, //10min + }, + }; +} + +const Leaderboard: NextPage<{ + rankings: any[]; +}> = ({ rankings }) => { + return
Leaderboard
; +}; + +export default Leaderboard; From 4daf402e8f2b81997c85b16a5038127800cc0c8a Mon Sep 17 00:00:00 2001 From: Tom Robiquet Date: Mon, 5 Jun 2023 17:14:15 +0300 Subject: [PATCH 02/40] fetch value in/out --- pages/leaderboard.tsx | 138 +++++++++++++++++++++++++++++++++--------- 1 file changed, 108 insertions(+), 30 deletions(-) diff --git a/pages/leaderboard.tsx b/pages/leaderboard.tsx index e16f2fde6..da9939354 100644 --- a/pages/leaderboard.tsx +++ b/pages/leaderboard.tsx @@ -1,19 +1,15 @@ -import { GraphQLClient } from "graphql-request"; -import { endpointOptions, graphQlEndpoint } from "lib/constants"; -import { NextPage } from "next"; import { AssetId, + create, getMarketIdOf, + IOBaseAssetId, IOMarketOutcomeAssetId, - mainnet, - mainnetIndexer, parseAssetId, - RpcContext, - Sdk, ZeitgeistIpfs, } from "@zeitgeistpm/sdk-next"; -import { create, mainnetRpc } from "@zeitgeistpm/sdk-next"; import Decimal from "decimal.js"; +import { endpointOptions, graphQlEndpoint } from "lib/constants"; +import { NextPage } from "next"; type Trade = { marketId: number; @@ -25,12 +21,34 @@ type Trade = { type: "trade" | "redeem"; }; +type AccountId = string; + type Traders = { - [key: string]: Trade[]; + [key: AccountId]: Trade[]; +}; + +type MarketTotals = { + [key: MarketId]: { + // marketId: number; + baseAsset: AssetId; + baseAssetIn: Decimal; + baseAssetOut: Decimal; + }; +}; + +type MarketId = number; + +type TradersByMarket = { + [key: AccountId]: MarketTotals; +}; + +type Ranked = { + accountId: string; + profit: Decimal; }; export async function getStaticProps() { - const client = new GraphQLClient(graphQlEndpoint); + // const client = new GraphQLClient(graphQlEndpoint); // const sdk= await create(mainnet()); const sdk = await create({ provider: endpointOptions.map((e) => e.value), @@ -38,7 +56,11 @@ export async function getStaticProps() { storage: ZeitgeistIpfs(), }); - const { historicalSwaps } = await sdk.indexer.historicalSwaps(); + const { historicalSwaps } = await sdk.indexer.historicalSwaps({ + where: { + // accountId_eq: "dDywmamjrDkaT18ybCRJBfax65CoxJNSWGZfwiQrbkAe95wq3", + }, + }); console.log(historicalSwaps); const tradersWithSwaps = historicalSwaps.reduce( @@ -82,36 +104,92 @@ export async function getStaticProps() { ); console.log(tradersWithSwaps); - const { historicalAccountBalances } = + const { historicalAccountBalances: redeemEvents } = await sdk.indexer.historicalAccountBalances({ where: { event_contains: "TokensRedeemed" }, }); - console.log(historicalAccountBalances); - historicalAccountBalances.forEach((redeem) => { + console.log(redeemEvents); + redeemEvents.forEach((redeem) => { const trades = tradersWithSwaps[redeem.accountId]; - const assetInId = parseAssetId(redeem.assetId).unwrap(); + // probably this check is needed as accounts can aquire tokens via buy full sell or transfer + if (trades) { + const assetInId = parseAssetId(redeem.assetId).unwrap(); - const marketId = IOMarketOutcomeAssetId.is(assetInId) - ? getMarketIdOf(assetInId) - : undefined; - const redeemTrade: Trade = { - marketId, - // baseAsset: baseAsset, - assetIn: assetInId, - assetOut: { Ztg: null }, - amountIn: new Decimal(redeem.dBalance).abs(), - amountOut: new Decimal(redeem.dBalance).abs(), - type: "redeem", - }; + const marketId = IOMarketOutcomeAssetId.is(assetInId) + ? getMarketIdOf(assetInId) + : undefined; + const redeemTrade: Trade = { + marketId, + // baseAsset: baseAsset, + assetIn: assetInId, + assetOut: { Ztg: null }, + amountIn: new Decimal(redeem.dBalance).abs(), + amountOut: new Decimal(redeem.dBalance).abs(), + type: "redeem", + }; - trades.push(redeemTrade); + trades.push(redeemTrade); - tradersWithSwaps[redeem.accountId] = trades; + tradersWithSwaps[redeem.accountId] = trades; + } }); - console.log(tradersWithSwaps); + //loop through accounts and trades, total up baseAsset in and out for each market + const tradersAggregatedByMarket = Object.keys( + tradersWithSwaps, + ).reduce((traders, accountId, index) => { + const swaps = tradersWithSwaps[accountId]; + if (!swaps) return traders; + + const marketTotal = swaps.reduce((markets, swap) => { + let baseAssetSwapType: "in" | "out" | undefined; + let baseAssetAmount: Decimal | undefined; + let baseAsset: AssetId; + + if (IOBaseAssetId.is(swap.assetIn)) { + baseAssetSwapType = "in"; + baseAssetAmount = swap.amountIn; + baseAsset = swap.assetIn; + } else if (IOBaseAssetId.is(swap.assetOut)) { + baseAssetSwapType = "out"; + baseAssetAmount = swap.amountOut; + baseAsset = swap.assetOut; + } + + if (!baseAssetSwapType) return markets; + + const market = markets[swap.marketId]; + if (market != null) { + markets[swap.marketId] = { + ...market, + baseAssetIn: (baseAssetSwapType === "in" + ? baseAssetAmount + : new Decimal(0) + ).plus(market.baseAssetIn), + baseAssetOut: (baseAssetSwapType === "out" + ? baseAssetAmount + : new Decimal(0) + ).plus(market.baseAssetOut), + }; + } else { + markets[swap.marketId] = { + baseAsset: baseAsset, + baseAssetIn: + baseAssetSwapType === "in" ? baseAssetAmount : new Decimal(0), + baseAssetOut: + baseAssetSwapType === "out" ? baseAssetAmount : new Decimal(0), + }; + } + return markets; + }, {}); + console.log(marketTotal); + + return { ...traders, [accountId]: marketTotal }; + }, {}); + + console.log(tradersAggregatedByMarket); const rankings = []; return { From a452e9dc46f18a56d4b6d5ad517eebb2b01d3453 Mon Sep 17 00:00:00 2001 From: Tom Robiquet Date: Mon, 5 Jun 2023 18:42:59 +0300 Subject: [PATCH 03/40] aggregate, sort and render users --- pages/leaderboard.tsx | 65 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 6 deletions(-) diff --git a/pages/leaderboard.tsx b/pages/leaderboard.tsx index da9939354..21b430368 100644 --- a/pages/leaderboard.tsx +++ b/pages/leaderboard.tsx @@ -8,8 +8,9 @@ import { ZeitgeistIpfs, } from "@zeitgeistpm/sdk-next"; import Decimal from "decimal.js"; -import { endpointOptions, graphQlEndpoint } from "lib/constants"; +import { endpointOptions, graphQlEndpoint, ZTG } from "lib/constants"; import { NextPage } from "next"; +import Link from "next/link"; type Trade = { marketId: number; @@ -42,9 +43,9 @@ type TradersByMarket = { [key: AccountId]: MarketTotals; }; -type Ranked = { +type Rank = { accountId: string; - profit: Decimal; + profit: number; }; export async function getStaticProps() { @@ -56,6 +57,11 @@ export async function getStaticProps() { storage: ZeitgeistIpfs(), }); + const { markets } = await sdk.indexer.markets(); + + // const marketsMap = markets.reduce((mMap, market) => { + // return { ...mMap, [market.marketId]: market }; + // }, {}); const { historicalSwaps } = await sdk.indexer.historicalSwaps({ where: { // accountId_eq: "dDywmamjrDkaT18ybCRJBfax65CoxJNSWGZfwiQrbkAe95wq3", @@ -191,7 +197,32 @@ export async function getStaticProps() { console.log(tradersAggregatedByMarket); - const rankings = []; + const tradeProfits = Object.keys(tradersAggregatedByMarket).reduce( + (ranks, accountId) => { + const trader = tradersAggregatedByMarket[accountId]; + + const profit = Object.keys(trader).reduce((total, marketId) => { + const market = trader[marketId]; + + return total.plus(market.baseAssetOut).minus(market.baseAssetIn); + }, new Decimal(0)); + + return { ...ranks, [accountId]: profit.div(ZTG).toNumber() }; + }, + {}, + ); + + console.log(tradeProfits); + + const rankings = Object.keys(tradeProfits) + .reduce((rankings, accountId) => { + rankings.push({ accountId, profit: tradeProfits[accountId] }); + return rankings; + }, []) + .sort((a, b) => b.profit - a.profit); + + console.log(rankings); + return { props: { rankings, @@ -201,9 +232,31 @@ export async function getStaticProps() { } const Leaderboard: NextPage<{ - rankings: any[]; + rankings: Rank[]; }> = ({ rankings }) => { - return
Leaderboard
; + return ( +
+
Most Profit
+
+ {rankings.map((rank, index) => ( +
+
{index + 1}
+ + {rank.accountId} + +
+ {rank.profit.toFixed(0)} ZTG +
+
+ ))} +
+
+ ); }; export default Leaderboard; From ca41d2db26ee80479f6ba8c78f22b711fba93e72 Mon Sep 17 00:00:00 2001 From: Tom Robiquet Date: Mon, 5 Jun 2023 18:48:07 +0300 Subject: [PATCH 04/40] todo --- pages/leaderboard.tsx | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/pages/leaderboard.tsx b/pages/leaderboard.tsx index 21b430368..936643257 100644 --- a/pages/leaderboard.tsx +++ b/pages/leaderboard.tsx @@ -12,6 +12,15 @@ import { endpointOptions, graphQlEndpoint, ZTG } from "lib/constants"; import { NextPage } from "next"; import Link from "next/link"; +//todo: +// wait for market resolution to count profit +// convert to $ +// support different base assets +// display most profitable market? +// include buy/sell full set events +// styling +// identity + type Trade = { marketId: number; // baseAsset: AssetId; @@ -241,12 +250,7 @@ const Leaderboard: NextPage<{ {rankings.map((rank, index) => (
{index + 1}
- + {rank.accountId}
From 59930cfd7f217e151ac8ac478669024356e1cebd Mon Sep 17 00:00:00 2001 From: Tom Robiquet Date: Tue, 13 Jun 2023 14:55:02 +0300 Subject: [PATCH 05/40] reduce fee buffer --- components/portfolio/DepositButton.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/portfolio/DepositButton.tsx b/components/portfolio/DepositButton.tsx index eb22e6133..bc402348f 100644 --- a/components/portfolio/DepositButton.tsx +++ b/components/portfolio/DepositButton.tsx @@ -124,7 +124,7 @@ const DepositModal = ({ if (!changedByUser) return; //assumes source chain fee is paid in currency that is being transferred - const maxTransferAmount = balance.minus(fee?.mul(1.01) ?? 0); //add 1% buffer to fee + const maxTransferAmount = balance.minus(fee?.mul(1.001) ?? 0); //add 0.1% buffer to fee if (name === "percentage") { setValue( "amount", From 8c2f5bc66b6f9ebefee4b761c6dd6d2cd51ad8b9 Mon Sep 17 00:00:00 2001 From: Tom Robiquet Date: Tue, 13 Jun 2023 14:55:24 +0300 Subject: [PATCH 06/40] fetch base asset prices --- pages/leaderboard.tsx | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/pages/leaderboard.tsx b/pages/leaderboard.tsx index 936643257..eabc51396 100644 --- a/pages/leaderboard.tsx +++ b/pages/leaderboard.tsx @@ -9,6 +9,7 @@ import { } from "@zeitgeistpm/sdk-next"; import Decimal from "decimal.js"; import { endpointOptions, graphQlEndpoint, ZTG } from "lib/constants"; +import { FOREIGN_ASSET_METADATA } from "lib/constants/foreign-asset"; import { NextPage } from "next"; import Link from "next/link"; @@ -57,6 +58,37 @@ type Rank = { profit: number; }; +type BasePrices = { + [key: string | "ztg"]: [number, number][]; +}; + +const getBaseAssetHistoricalPrices = async (): Promise => { + const coinGeckoIds = [ + ...Object.values(FOREIGN_ASSET_METADATA).map((asset) => asset.coinGeckoId), + "zeitgeist", + ]; + + const pricesRes = await Promise.all( + coinGeckoIds.map((id) => + fetch( + `https://api.coingecko.com/api/v3/coins/${id}/market_chart?vs_currency=usd&days=max`, + ), + ), + ); + + const prices = await Promise.all(pricesRes.map((res) => res.json())); + const assetIds = Object.keys(FOREIGN_ASSET_METADATA); + + const pricesObj = prices.reduce((obj, assetPrices, index) => { + obj[assetIds[index]] = assetPrices.prices; + return obj; + }, {}); + + pricesObj["ztg"] = prices.at(-1).prices; + + return pricesObj; +}; + export async function getStaticProps() { // const client = new GraphQLClient(graphQlEndpoint); // const sdk= await create(mainnet()); @@ -66,6 +98,8 @@ export async function getStaticProps() { storage: ZeitgeistIpfs(), }); + const basePrices = await getBaseAssetHistoricalPrices(); + const { markets } = await sdk.indexer.markets(); // const marketsMap = markets.reduce((mMap, market) => { From 3156311d9595257d9a32b94f7e433ba3bc53dd76 Mon Sep 17 00:00:00 2001 From: Tom Robiquet Date: Tue, 13 Jun 2023 15:48:00 +0300 Subject: [PATCH 07/40] denominate in $ --- pages/leaderboard.tsx | 60 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 9 deletions(-) diff --git a/pages/leaderboard.tsx b/pages/leaderboard.tsx index eabc51396..3e518587b 100644 --- a/pages/leaderboard.tsx +++ b/pages/leaderboard.tsx @@ -1,8 +1,10 @@ import { AssetId, + BaseAssetId, create, getMarketIdOf, IOBaseAssetId, + IOForeignAssetId, IOMarketOutcomeAssetId, parseAssetId, ZeitgeistIpfs, @@ -41,7 +43,7 @@ type Traders = { type MarketTotals = { [key: MarketId]: { // marketId: number; - baseAsset: AssetId; + baseAsset: BaseAssetId; baseAssetIn: Decimal; baseAssetOut: Decimal; }; @@ -62,6 +64,33 @@ type BasePrices = { [key: string | "ztg"]: [number, number][]; }; +const datesAreOnSameDay = (first: Date, second: Date) => + first.getFullYear() === second.getFullYear() && + first.getMonth() === second.getMonth() && + first.getDate() === second.getDate(); + +const findPrice = (timestamp: number, prices: [number, number][]) => { + const date = new Date(Number(timestamp)); + + const price = prices.find((p) => { + return datesAreOnSameDay(date, new Date(p[0])); + }); + + return price[1]; +}; + +const lookupPrice = ( + basePrices: BasePrices, + baseAsset: BaseAssetId, + timestamp: number, +) => { + const prices = IOForeignAssetId.is(baseAsset) + ? basePrices[baseAsset.ForeignAsset] + : basePrices["ztg"]; + + return findPrice(timestamp, prices); +}; + const getBaseAssetHistoricalPrices = async (): Promise => { const coinGeckoIds = [ ...Object.values(FOREIGN_ASSET_METADATA).map((asset) => asset.coinGeckoId), @@ -195,7 +224,7 @@ export async function getStaticProps() { const marketTotal = swaps.reduce((markets, swap) => { let baseAssetSwapType: "in" | "out" | undefined; let baseAssetAmount: Decimal | undefined; - let baseAsset: AssetId; + let baseAsset: BaseAssetId; if (IOBaseAssetId.is(swap.assetIn)) { baseAssetSwapType = "in"; @@ -245,9 +274,24 @@ export async function getStaticProps() { const trader = tradersAggregatedByMarket[accountId]; const profit = Object.keys(trader).reduce((total, marketId) => { - const market = trader[marketId]; - - return total.plus(market.baseAssetOut).minus(market.baseAssetIn); + const marketTotal = trader[marketId]; + + const market = markets.find((m) => m.marketId === Number(marketId)); + + if (market.status === "Resolved") { + const diff = marketTotal.baseAssetOut.minus(marketTotal.baseAssetIn); + const endTimestamp = market.period.end; + + const marketEndBaseAssetPrice = lookupPrice( + basePrices, + marketTotal.baseAsset, + endTimestamp, + ); + const usdProfitLoss = diff.mul(marketEndBaseAssetPrice); + return total.plus(usdProfitLoss); + } else { + return total; + } }, new Decimal(0)); return { ...ranks, [accountId]: profit.div(ZTG).toNumber() }; @@ -265,7 +309,7 @@ export async function getStaticProps() { .sort((a, b) => b.profit - a.profit); console.log(rankings); - + //take top 10 and find identities here return { props: { rankings, @@ -287,9 +331,7 @@ const Leaderboard: NextPage<{ {rank.accountId} -
- {rank.profit.toFixed(0)} ZTG -
+
${rank.profit.toFixed(0)}
))}
From 2e72a3011772a96773b5fd26d1f1416522fb7022 Mon Sep 17 00:00:00 2001 From: Tom Robiquet Date: Tue, 13 Jun 2023 16:18:36 +0300 Subject: [PATCH 08/40] load identities --- pages/leaderboard.tsx | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/pages/leaderboard.tsx b/pages/leaderboard.tsx index 3e518587b..1671560e0 100644 --- a/pages/leaderboard.tsx +++ b/pages/leaderboard.tsx @@ -14,15 +14,13 @@ import { endpointOptions, graphQlEndpoint, ZTG } from "lib/constants"; import { FOREIGN_ASSET_METADATA } from "lib/constants/foreign-asset"; import { NextPage } from "next"; import Link from "next/link"; +import Avatar from "components/ui/Avatar"; //todo: -// wait for market resolution to count profit -// convert to $ -// support different base assets // display most profitable market? // include buy/sell full set events // styling -// identity +// handle staging price (no ztg price history) type Trade = { marketId: number; @@ -58,6 +56,7 @@ type TradersByMarket = { type Rank = { accountId: string; profit: number; + name?: string; }; type BasePrices = { @@ -278,7 +277,7 @@ export async function getStaticProps() { const market = markets.find((m) => m.marketId === Number(marketId)); - if (market.status === "Resolved") { + if (market?.status === "Resolved") { const diff = marketTotal.baseAssetOut.minus(marketTotal.baseAssetIn); const endTimestamp = market.period.end; @@ -308,11 +307,22 @@ export async function getStaticProps() { }, []) .sort((a, b) => b.profit - a.profit); - console.log(rankings); - //take top 10 and find identities here + const top10 = rankings.slice(0, 10); + + const indentities = await Promise.all( + top10.map((player) => sdk.api.query.identity.identityOf(player.accountId)), + ); + + const names: (string | undefined)[] = indentities.map( + (i) => (i.toHuman() as any)?.info?.display.Raw, + ); + return { props: { - rankings, + rankings: top10.map((player, index) => ({ + ...player, + name: names[index] ?? null, + })), revalidate: 10 * 60, //10min }, }; @@ -322,14 +332,18 @@ const Leaderboard: NextPage<{ rankings: Rank[]; }> = ({ rankings }) => { return ( -
+
Most Profit
-
+
{rankings.map((rank, index) => ( -
+
{index + 1}
- - {rank.accountId} + + + {rank.name ?? rank.accountId}
${rank.profit.toFixed(0)}
From 58128a903fd62229758680be950eab613247e250 Mon Sep 17 00:00:00 2001 From: Tom Robiquet Date: Tue, 13 Jun 2023 17:37:41 +0300 Subject: [PATCH 09/40] display top markets --- pages/leaderboard.tsx | 119 +++++++++++++++++++++++++++++------------- 1 file changed, 83 insertions(+), 36 deletions(-) diff --git a/pages/leaderboard.tsx b/pages/leaderboard.tsx index 1671560e0..e0c068bf3 100644 --- a/pages/leaderboard.tsx +++ b/pages/leaderboard.tsx @@ -53,10 +53,25 @@ type TradersByMarket = { [key: AccountId]: MarketTotals; }; +type MarketSummary = { + marketId: number; + question: string; + baseAssetId: BaseAssetId; + profit: number; +}; + +type TradersSummary = { + [key: AccountId]: { + profit: number; + markets: MarketSummary[]; + }; +}; + type Rank = { accountId: string; profit: number; name?: string; + markets: MarketSummary[]; }; type BasePrices = { @@ -212,6 +227,7 @@ export async function getStaticProps() { tradersWithSwaps[redeem.accountId] = trades; } }); + //fetch and process buy/sell full sets //loop through accounts and trades, total up baseAsset in and out for each market const tradersAggregatedByMarket = Object.keys( @@ -268,46 +284,64 @@ export async function getStaticProps() { console.log(tradersAggregatedByMarket); - const tradeProfits = Object.keys(tradersAggregatedByMarket).reduce( - (ranks, accountId) => { - const trader = tradersAggregatedByMarket[accountId]; + const tradeProfits = Object.keys( + tradersAggregatedByMarket, + ).reduce((ranks, accountId) => { + const trader = tradersAggregatedByMarket[accountId]; - const profit = Object.keys(trader).reduce((total, marketId) => { - const marketTotal = trader[marketId]; + const marketsSummary: MarketSummary[] = []; + const profit = Object.keys(trader).reduce((total, marketId) => { + const marketTotal = trader[marketId]; - const market = markets.find((m) => m.marketId === Number(marketId)); + const market = markets.find((m) => m.marketId === Number(marketId)); - if (market?.status === "Resolved") { - const diff = marketTotal.baseAssetOut.minus(marketTotal.baseAssetIn); - const endTimestamp = market.period.end; + if (market?.status === "Resolved") { + const diff = marketTotal.baseAssetOut.minus(marketTotal.baseAssetIn); - const marketEndBaseAssetPrice = lookupPrice( - basePrices, - marketTotal.baseAsset, - endTimestamp, - ); - const usdProfitLoss = diff.mul(marketEndBaseAssetPrice); - return total.plus(usdProfitLoss); - } else { - return total; - } - }, new Decimal(0)); + marketsSummary.push({ + question: market.question, + marketId: market.marketId, + baseAssetId: marketTotal.baseAsset, + profit: diff.div(ZTG).toNumber(), + }); - return { ...ranks, [accountId]: profit.div(ZTG).toNumber() }; - }, - {}, - ); + const endTimestamp = market.period.end; + + const marketEndBaseAssetPrice = lookupPrice( + basePrices, + marketTotal.baseAsset, + endTimestamp, + ); + const usdProfitLoss = diff.mul(marketEndBaseAssetPrice); + return total.plus(usdProfitLoss); + } else { + return total; + } + }, new Decimal(0)); + + return { + ...ranks, + [accountId]: { + profit: profit.div(ZTG).toNumber(), + markets: marketsSummary, + }, + }; + }, {}); console.log(tradeProfits); const rankings = Object.keys(tradeProfits) .reduce((rankings, accountId) => { - rankings.push({ accountId, profit: tradeProfits[accountId] }); + rankings.push({ + accountId, + profit: tradeProfits[accountId].profit, + markets: tradeProfits[accountId].markets, + }); return rankings; }, []) .sort((a, b) => b.profit - a.profit); - const top10 = rankings.slice(0, 10); + const top10 = rankings.slice(0, 100); const indentities = await Promise.all( top10.map((player) => sdk.api.query.identity.identityOf(player.accountId)), @@ -336,16 +370,29 @@ const Leaderboard: NextPage<{
Most Profit
{rankings.map((rank, index) => ( -
-
{index + 1}
- - - {rank.name ?? rank.accountId} - -
${rank.profit.toFixed(0)}
+
+
+
{index + 1}
+ + + {rank.name ?? rank.accountId} + +
${rank.profit.toFixed(0)}
+
+
+ {rank.markets + .sort((a, b) => b.profit - a.profit) + .slice(0, 3) + .map((market) => ( +
+
{market.question}
+
{market.profit.toFixed()}
+
+ ))} +
))}
From df892943633366ce597e0463977bb451af8152a3 Mon Sep 17 00:00:00 2001 From: Tom Robiquet Date: Wed, 14 Jun 2023 11:29:21 +0300 Subject: [PATCH 10/40] look up asset symbol --- lib/constants/foreign-asset.ts | 12 ++++++++++++ pages/leaderboard.tsx | 10 ++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/lib/constants/foreign-asset.ts b/lib/constants/foreign-asset.ts index 4315ef389..883c9c56d 100644 --- a/lib/constants/foreign-asset.ts +++ b/lib/constants/foreign-asset.ts @@ -1,3 +1,4 @@ +import { BaseAssetId, IOForeignAssetId } from "@zeitgeistpm/sdk-next"; import { ChainName } from "./chains"; type ForeignAssetMetadata = { @@ -19,6 +20,17 @@ export const lookupAssetImagePath = (foreignAssetId?: number) => { } }; +export const lookupAssetSymbol = (baseAssetId?: BaseAssetId) => { + const foreignAssetId = IOForeignAssetId.is(baseAssetId) + ? baseAssetId.ForeignAsset + : null; + if (foreignAssetId == null) { + return "ZTG"; + } else { + return FOREIGN_ASSET_METADATA[foreignAssetId].tokenSymbol; + } +}; + const BATTERY_STATION_FOREIGN_ASSET_METADATA: ForeignAssetMetadata = { 0: { image: "/currencies/dot.png", diff --git a/pages/leaderboard.tsx b/pages/leaderboard.tsx index e0c068bf3..17456f411 100644 --- a/pages/leaderboard.tsx +++ b/pages/leaderboard.tsx @@ -11,7 +11,10 @@ import { } from "@zeitgeistpm/sdk-next"; import Decimal from "decimal.js"; import { endpointOptions, graphQlEndpoint, ZTG } from "lib/constants"; -import { FOREIGN_ASSET_METADATA } from "lib/constants/foreign-asset"; +import { + FOREIGN_ASSET_METADATA, + lookupAssetSymbol, +} from "lib/constants/foreign-asset"; import { NextPage } from "next"; import Link from "next/link"; import Avatar from "components/ui/Avatar"; @@ -389,7 +392,10 @@ const Leaderboard: NextPage<{ .map((market) => (
{market.question}
-
{market.profit.toFixed()}
+
+ {market.profit.toFixed()}{" "} + {lookupAssetSymbol(market.baseAssetId)} +
))}
From 8196f11b605bf20f615a9200a300feb45592cfbd Mon Sep 17 00:00:00 2001 From: Tom Robiquet Date: Wed, 14 Jun 2023 11:41:57 +0300 Subject: [PATCH 11/40] fix staging prices --- pages/leaderboard.tsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/pages/leaderboard.tsx b/pages/leaderboard.tsx index 17456f411..48e220823 100644 --- a/pages/leaderboard.tsx +++ b/pages/leaderboard.tsx @@ -10,7 +10,12 @@ import { ZeitgeistIpfs, } from "@zeitgeistpm/sdk-next"; import Decimal from "decimal.js"; -import { endpointOptions, graphQlEndpoint, ZTG } from "lib/constants"; +import { + endpointOptions, + environment, + graphQlEndpoint, + ZTG, +} from "lib/constants"; import { FOREIGN_ASSET_METADATA, lookupAssetSymbol, @@ -23,11 +28,9 @@ import Avatar from "components/ui/Avatar"; // display most profitable market? // include buy/sell full set events // styling -// handle staging price (no ztg price history) type Trade = { marketId: number; - // baseAsset: AssetId; amountIn: Decimal; amountOut: Decimal; assetIn: AssetId; @@ -43,7 +46,6 @@ type Traders = { type MarketTotals = { [key: MarketId]: { - // marketId: number; baseAsset: BaseAssetId; baseAssetIn: Decimal; baseAssetOut: Decimal; @@ -101,6 +103,8 @@ const lookupPrice = ( baseAsset: BaseAssetId, timestamp: number, ) => { + //BSR has been live before some assets existed, so no price data is available + if (environment === "staging") return 1; const prices = IOForeignAssetId.is(baseAsset) ? basePrices[baseAsset.ForeignAsset] : basePrices["ztg"]; From def6a01d89cde102e44dd2cb58c4f226dff3c455 Mon Sep 17 00:00:00 2001 From: Tom Robiquet Date: Wed, 14 Jun 2023 11:50:35 +0300 Subject: [PATCH 12/40] tidy and strict null --- pages/leaderboard.tsx | 112 +++++++++++++++++++----------------------- 1 file changed, 50 insertions(+), 62 deletions(-) diff --git a/pages/leaderboard.tsx b/pages/leaderboard.tsx index 48e220823..38cd1e3e3 100644 --- a/pages/leaderboard.tsx +++ b/pages/leaderboard.tsx @@ -25,7 +25,6 @@ import Link from "next/link"; import Avatar from "components/ui/Avatar"; //todo: -// display most profitable market? // include buy/sell full set events // styling @@ -95,7 +94,7 @@ const findPrice = (timestamp: number, prices: [number, number][]) => { return datesAreOnSameDay(date, new Date(p[0])); }); - return price[1]; + return price?.[1]; }; const lookupPrice = ( @@ -162,53 +161,45 @@ export async function getStaticProps() { }); console.log(historicalSwaps); - const tradersWithSwaps = historicalSwaps.reduce( - (traders, swap, index) => { - const trades = traders[swap.accountId]; - - const assetInId = parseAssetId(swap.assetIn).unwrap(); - const assetOutId = parseAssetId(swap.assetOut).unwrap(); - - let marketId: number | undefined; - let baseAsset: AssetId | undefined; - if (IOMarketOutcomeAssetId.is(assetInId)) { - marketId = getMarketIdOf(assetInId); - baseAsset = assetOutId; - } else if (IOMarketOutcomeAssetId.is(assetOutId)) { - marketId = getMarketIdOf(assetOutId); - baseAsset = assetInId; - } + const tradersWithSwaps = historicalSwaps.reduce((traders, swap) => { + const trades = traders[swap.accountId]; - const trade: Trade = { - marketId, - // baseAsset: baseAsset, - assetIn: assetInId, - assetOut: assetOutId, - amountIn: new Decimal(swap.assetAmountIn), - amountOut: new Decimal(swap.assetAmountOut), - type: "trade", - }; + const assetInId = parseAssetId(swap.assetIn).unwrap(); + const assetOutId = parseAssetId(swap.assetOut).unwrap(); - if (trades) { - trades.push(trade); + let marketId: number | undefined; + if (IOMarketOutcomeAssetId.is(assetInId)) { + marketId = getMarketIdOf(assetInId); + } else if (IOMarketOutcomeAssetId.is(assetOutId)) { + marketId = getMarketIdOf(assetOutId); + } - traders[swap.accountId] = trades; - } else { - traders[swap.accountId] = [trade]; - } + if (marketId === undefined) return traders; - return traders; - }, - {}, - ); + const trade: Trade = { + marketId, + assetIn: assetInId, + assetOut: assetOutId, + amountIn: new Decimal(swap.assetAmountIn), + amountOut: new Decimal(swap.assetAmountOut), + type: "trade", + }; + + if (trades) { + trades.push(trade); + traders[swap.accountId] = trades; + } else { + traders[swap.accountId] = [trade]; + } + + return traders; + }, {}); - console.log(tradersWithSwaps); const { historicalAccountBalances: redeemEvents } = await sdk.indexer.historicalAccountBalances({ where: { event_contains: "TokensRedeemed" }, }); - console.log(redeemEvents); redeemEvents.forEach((redeem) => { const trades = tradersWithSwaps[redeem.accountId]; @@ -219,34 +210,36 @@ export async function getStaticProps() { const marketId = IOMarketOutcomeAssetId.is(assetInId) ? getMarketIdOf(assetInId) : undefined; - const redeemTrade: Trade = { - marketId, - // baseAsset: baseAsset, - assetIn: assetInId, - assetOut: { Ztg: null }, - amountIn: new Decimal(redeem.dBalance).abs(), - amountOut: new Decimal(redeem.dBalance).abs(), - type: "redeem", - }; - - trades.push(redeemTrade); - - tradersWithSwaps[redeem.accountId] = trades; + + if (marketId !== undefined) { + const redeemTrade: Trade = { + marketId, + assetIn: assetInId, + assetOut: { Ztg: null }, + amountIn: new Decimal(redeem.dBalance).abs(), + amountOut: new Decimal(redeem.dBalance).abs(), + type: "redeem", + }; + + trades.push(redeemTrade); + + tradersWithSwaps[redeem.accountId] = trades; + } } }); - //fetch and process buy/sell full sets + //TODO: fetch and process buy/sell full sets //loop through accounts and trades, total up baseAsset in and out for each market const tradersAggregatedByMarket = Object.keys( tradersWithSwaps, - ).reduce((traders, accountId, index) => { + ).reduce((traders, accountId) => { const swaps = tradersWithSwaps[accountId]; if (!swaps) return traders; const marketTotal = swaps.reduce((markets, swap) => { let baseAssetSwapType: "in" | "out" | undefined; let baseAssetAmount: Decimal | undefined; - let baseAsset: BaseAssetId; + let baseAsset: BaseAssetId | undefined; if (IOBaseAssetId.is(swap.assetIn)) { baseAssetSwapType = "in"; @@ -258,7 +251,7 @@ export async function getStaticProps() { baseAsset = swap.assetOut; } - if (!baseAssetSwapType) return markets; + if (!baseAssetSwapType || !baseAsset || !baseAssetAmount) return markets; const market = markets[swap.marketId]; if (market != null) { @@ -284,13 +277,10 @@ export async function getStaticProps() { } return markets; }, {}); - console.log(marketTotal); return { ...traders, [accountId]: marketTotal }; }, {}); - console.log(tradersAggregatedByMarket); - const tradeProfits = Object.keys( tradersAggregatedByMarket, ).reduce((ranks, accountId) => { @@ -306,7 +296,7 @@ export async function getStaticProps() { const diff = marketTotal.baseAssetOut.minus(marketTotal.baseAssetIn); marketsSummary.push({ - question: market.question, + question: market.question!, marketId: market.marketId, baseAssetId: marketTotal.baseAsset, profit: diff.div(ZTG).toNumber(), @@ -335,8 +325,6 @@ export async function getStaticProps() { }; }, {}); - console.log(tradeProfits); - const rankings = Object.keys(tradeProfits) .reduce((rankings, accountId) => { rankings.push({ From 9e6f7689368dbccbcbcef9185c4d05766c91a7e0 Mon Sep 17 00:00:00 2001 From: Tom Robiquet Date: Fri, 16 Jun 2023 14:30:26 +0300 Subject: [PATCH 13/40] fetch full set txs --- pages/leaderboard.tsx | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/pages/leaderboard.tsx b/pages/leaderboard.tsx index 38cd1e3e3..de1602d6d 100644 --- a/pages/leaderboard.tsx +++ b/pages/leaderboard.tsx @@ -28,6 +28,14 @@ import Avatar from "components/ui/Avatar"; // include buy/sell full set events // styling +// Track trades, buy full set, sell full set, + +// Buy Full Set events +// Deposited includes all assets +// DepositedEndowed includes all assets +// EndowedBoughtCompleteSet includes all assets +// BoughtCompleteSet only includes one asset + type Trade = { marketId: number; amountIn: Decimal; @@ -159,7 +167,7 @@ export async function getStaticProps() { // accountId_eq: "dDywmamjrDkaT18ybCRJBfax65CoxJNSWGZfwiQrbkAe95wq3", }, }); - console.log(historicalSwaps); + // console.log(historicalSwaps); const tradersWithSwaps = historicalSwaps.reduce((traders, swap) => { const trades = traders[swap.accountId]; @@ -229,6 +237,29 @@ export async function getStaticProps() { }); //TODO: fetch and process buy/sell full sets + const { historicalAccountBalances: buyFullSetEvents } = + await sdk.indexer.historicalAccountBalances({ + where: { + AND: [ + { + event_contains: "BoughtComplete", + }, + { + OR: [{ event_contains: "Deposited", assetId_not_contains: "pool" }], + }, + ], + }, + }); + + const { historicalAccountBalances: sellFullSetEvents } = + await sdk.indexer.historicalAccountBalances({ + where: { + event_contains: "SoldComplete", + }, + }); + + console.log(buyFullSetEvents); + //loop through accounts and trades, total up baseAsset in and out for each market const tradersAggregatedByMarket = Object.keys( tradersWithSwaps, From 35f1d0058a6b7a4f28f1116d853c561ca4fd3fec Mon Sep 17 00:00:00 2001 From: Tom Robiquet Date: Fri, 16 Jun 2023 16:47:45 +0300 Subject: [PATCH 14/40] types --- pages/leaderboard.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/leaderboard.tsx b/pages/leaderboard.tsx index de1602d6d..6e0dbacc5 100644 --- a/pages/leaderboard.tsx +++ b/pages/leaderboard.tsx @@ -42,7 +42,7 @@ type Trade = { amountOut: Decimal; assetIn: AssetId; assetOut: AssetId; - type: "trade" | "redeem"; + type: "trade" | "redeem" | "sellFullSet" | "buyFullSet"; }; type AccountId = string; From bc01b14364a67f594389bd6d5354403b14a24f22 Mon Sep 17 00:00:00 2001 From: Tom Robiquet Date: Wed, 21 Jun 2023 12:24:32 +0300 Subject: [PATCH 15/40] refactor --- pages/leaderboard.tsx | 92 +++++++++++++++++++++++++------------------ 1 file changed, 54 insertions(+), 38 deletions(-) diff --git a/pages/leaderboard.tsx b/pages/leaderboard.tsx index 6e0dbacc5..81d1718a3 100644 --- a/pages/leaderboard.tsx +++ b/pages/leaderboard.tsx @@ -23,6 +23,7 @@ import { import { NextPage } from "next"; import Link from "next/link"; import Avatar from "components/ui/Avatar"; +import { formatNumberCompact } from "lib/util/format-compact"; //todo: // include buy/sell full set events @@ -40,8 +41,8 @@ type Trade = { marketId: number; amountIn: Decimal; amountOut: Decimal; - assetIn: AssetId; - assetOut: AssetId; + assetIn?: AssetId; + assetOut?: AssetId; type: "trade" | "redeem" | "sellFullSet" | "buyFullSet"; }; @@ -51,12 +52,14 @@ type Traders = { [key: AccountId]: Trade[]; }; +type MarketBaseDetails = { + baseAsset: BaseAssetId; + baseAssetIn: Decimal; + baseAssetOut: Decimal; +}; + type MarketTotals = { - [key: MarketId]: { - baseAsset: BaseAssetId; - baseAssetIn: Decimal; - baseAssetOut: Decimal; - }; + [key: MarketId]: MarketBaseDetails; }; type MarketId = number; @@ -89,7 +92,35 @@ type Rank = { type BasePrices = { [key: string | "ztg"]: [number, number][]; }; +type Event = { + accountId: string; + assetId: string; + blockNumber: number; + dBalance: any; + event: string; + id: string; + timestamp: any; +}; +const convertEventToTrade = (event: Event) => { + const assetInId = parseAssetId(event.assetId).unwrap(); + + const marketId = IOMarketOutcomeAssetId.is(assetInId) + ? getMarketIdOf(assetInId) + : undefined; + + if (marketId !== undefined) { + const trade: Trade = { + marketId, + assetIn: assetInId, + assetOut: { Ztg: null }, + amountIn: new Decimal(event.dBalance).abs(), + amountOut: new Decimal(event.dBalance).abs(), + type: "redeem", + }; + return trade; + } +}; const datesAreOnSameDay = (first: Date, second: Date) => first.getFullYear() === second.getFullYear() && first.getMonth() === second.getMonth() && @@ -208,35 +239,6 @@ export async function getStaticProps() { where: { event_contains: "TokensRedeemed" }, }); - redeemEvents.forEach((redeem) => { - const trades = tradersWithSwaps[redeem.accountId]; - - // probably this check is needed as accounts can aquire tokens via buy full sell or transfer - if (trades) { - const assetInId = parseAssetId(redeem.assetId).unwrap(); - - const marketId = IOMarketOutcomeAssetId.is(assetInId) - ? getMarketIdOf(assetInId) - : undefined; - - if (marketId !== undefined) { - const redeemTrade: Trade = { - marketId, - assetIn: assetInId, - assetOut: { Ztg: null }, - amountIn: new Decimal(redeem.dBalance).abs(), - amountOut: new Decimal(redeem.dBalance).abs(), - type: "redeem", - }; - - trades.push(redeemTrade); - - tradersWithSwaps[redeem.accountId] = trades; - } - } - }); - //TODO: fetch and process buy/sell full sets - const { historicalAccountBalances: buyFullSetEvents } = await sdk.indexer.historicalAccountBalances({ where: { @@ -258,6 +260,19 @@ export async function getStaticProps() { }, }); + redeemEvents.forEach((redeem) => { + const trades = tradersWithSwaps[redeem.accountId]; + + // probably this check is needed as accounts can aquire tokens via buy full sell or transfer + if (trades) { + const trade = convertEventToTrade(redeem); + + if (trade) trades.push(trade); + + tradersWithSwaps[redeem.accountId] = trades; + } + }); + console.log(buyFullSetEvents); //loop through accounts and trades, total up baseAsset in and out for each market @@ -391,6 +406,7 @@ export async function getStaticProps() { const Leaderboard: NextPage<{ rankings: Rank[]; }> = ({ rankings }) => { + console.log(rankings[0].markets); return (
Most Profit
@@ -411,12 +427,12 @@ const Leaderboard: NextPage<{
{rank.markets .sort((a, b) => b.profit - a.profit) - .slice(0, 3) + .slice(0, 20) // todo move this server side .map((market) => (
{market.question}
- {market.profit.toFixed()}{" "} + {formatNumberCompact(market.profit)}{" "} {lookupAssetSymbol(market.baseAssetId)}
From 932ba01115f3dde0f1d2fee2b07fd3b41b5a240d Mon Sep 17 00:00:00 2001 From: Tom Robiquet Date: Wed, 21 Jun 2023 14:07:10 +0300 Subject: [PATCH 16/40] more refactoring for new events --- pages/leaderboard.tsx | 157 +++++++++++++++++++++++++----------------- 1 file changed, 92 insertions(+), 65 deletions(-) diff --git a/pages/leaderboard.tsx b/pages/leaderboard.tsx index 81d1718a3..c2a6b1305 100644 --- a/pages/leaderboard.tsx +++ b/pages/leaderboard.tsx @@ -24,6 +24,7 @@ import { NextPage } from "next"; import Link from "next/link"; import Avatar from "components/ui/Avatar"; import { formatNumberCompact } from "lib/util/format-compact"; +import { parseAssetIdString } from "lib/util/parse-asset-id"; //todo: // include buy/sell full set events @@ -39,10 +40,10 @@ import { formatNumberCompact } from "lib/util/format-compact"; type Trade = { marketId: number; - amountIn: Decimal; - amountOut: Decimal; - assetIn?: AssetId; - assetOut?: AssetId; + baseAssetIn: Decimal; + baseAssetOut: Decimal; + // assetIn?: AssetId; + // assetOut?: AssetId; type: "trade" | "redeem" | "sellFullSet" | "buyFullSet"; }; @@ -53,7 +54,7 @@ type Traders = { }; type MarketBaseDetails = { - baseAsset: BaseAssetId; + // baseAsset: BaseAssetId; baseAssetIn: Decimal; baseAssetOut: Decimal; }; @@ -103,22 +104,27 @@ type Event = { }; const convertEventToTrade = (event: Event) => { - const assetInId = parseAssetId(event.assetId).unwrap(); + const assetId = parseAssetId(event.assetId).unwrap(); - const marketId = IOMarketOutcomeAssetId.is(assetInId) - ? getMarketIdOf(assetInId) + const marketId = IOMarketOutcomeAssetId.is(assetId) + ? getMarketIdOf(assetId) : undefined; if (marketId !== undefined) { - const trade: Trade = { - marketId, - assetIn: assetInId, - assetOut: { Ztg: null }, - amountIn: new Decimal(event.dBalance).abs(), - amountOut: new Decimal(event.dBalance).abs(), - type: "redeem", - }; - return trade; + if (event.event === "TokensRedeemed") { + const trade: Trade = { + marketId, + // assetIn: assetId, + // assetOut: { Ztg: null }, + baseAssetIn: new Decimal(0), + baseAssetOut: new Decimal(event.dBalance).abs(), + type: "redeem", + }; + return trade; + } else if (event.event === "SoldCompleteSet") { + } else if (event.event === "Deposited") { + } else if (event.event === "BoughtCompleteSet") { + } } }; const datesAreOnSameDay = (first: Date, second: Date) => @@ -205,22 +211,33 @@ export async function getStaticProps() { const assetInId = parseAssetId(swap.assetIn).unwrap(); const assetOutId = parseAssetId(swap.assetOut).unwrap(); + let baseAssetSwapType: "in" | "out" | undefined; let marketId: number | undefined; if (IOMarketOutcomeAssetId.is(assetInId)) { marketId = getMarketIdOf(assetInId); + baseAssetSwapType = "out"; } else if (IOMarketOutcomeAssetId.is(assetOutId)) { marketId = getMarketIdOf(assetOutId); + baseAssetSwapType = "in"; } if (marketId === undefined) return traders; const trade: Trade = { marketId, - assetIn: assetInId, - assetOut: assetOutId, - amountIn: new Decimal(swap.assetAmountIn), - amountOut: new Decimal(swap.assetAmountOut), + // assetIn: assetInId, + // assetOut: assetOutId, + // amountIn: new Decimal(swap.assetAmountIn), + // amountOut: new Decimal(swap.assetAmountOut), + baseAssetIn: + baseAssetSwapType === "in" + ? new Decimal(swap.assetAmountIn) + : new Decimal(0), + baseAssetOut: + baseAssetSwapType === "out" + ? new Decimal(swap.assetAmountOut) + : new Decimal(0), type: "trade", }; @@ -260,21 +277,38 @@ export async function getStaticProps() { }, }); - redeemEvents.forEach((redeem) => { - const trades = tradersWithSwaps[redeem.accountId]; + console.time("t"); + const fullSetEvents = [...buyFullSetEvents, ...sellFullSetEvents]; + + const uniqueFullSetEvents = fullSetEvents.reduce( + (uniqueEvents, event) => { + const duplicateEvent = uniqueEvents.find( + (entry) => entry.id === event.id, + ); + + if (!duplicateEvent) { + uniqueEvents.push(event); + } + + return uniqueEvents; + }, + [], + ); + console.log(uniqueFullSetEvents); + + [...redeemEvents, ...uniqueFullSetEvents].forEach((event) => { + const trades = tradersWithSwaps[event.accountId]; // probably this check is needed as accounts can aquire tokens via buy full sell or transfer if (trades) { - const trade = convertEventToTrade(redeem); + const trade = convertEventToTrade(event); if (trade) trades.push(trade); - tradersWithSwaps[redeem.accountId] = trades; + tradersWithSwaps[event.accountId] = trades; } }); - console.log(buyFullSetEvents); - //loop through accounts and trades, total up baseAsset in and out for each market const tradersAggregatedByMarket = Object.keys( tradersWithSwaps, @@ -282,46 +316,39 @@ export async function getStaticProps() { const swaps = tradersWithSwaps[accountId]; if (!swaps) return traders; - const marketTotal = swaps.reduce((markets, swap) => { - let baseAssetSwapType: "in" | "out" | undefined; - let baseAssetAmount: Decimal | undefined; - let baseAsset: BaseAssetId | undefined; - - if (IOBaseAssetId.is(swap.assetIn)) { - baseAssetSwapType = "in"; - baseAssetAmount = swap.amountIn; - baseAsset = swap.assetIn; - } else if (IOBaseAssetId.is(swap.assetOut)) { - baseAssetSwapType = "out"; - baseAssetAmount = swap.amountOut; - baseAsset = swap.assetOut; - } - - if (!baseAssetSwapType || !baseAsset || !baseAssetAmount) return markets; - - const market = markets[swap.marketId]; - if (market != null) { - markets[swap.marketId] = { - ...market, - baseAssetIn: (baseAssetSwapType === "in" - ? baseAssetAmount - : new Decimal(0) - ).plus(market.baseAssetIn), - baseAssetOut: (baseAssetSwapType === "out" - ? baseAssetAmount - : new Decimal(0) - ).plus(market.baseAssetOut), + const marketTotal = swaps.reduce((marketTotals, swap) => { + // let baseAssetSwapType: "in" | "out" | undefined; + // let baseAssetAmount: Decimal | undefined; + // let baseAsset: BaseAssetId | undefined; + + // if (IOBaseAssetId.is(swap.assetIn)) { + // baseAssetSwapType = "in"; + // baseAssetAmount = swap.amountIn; + // baseAsset = swap.assetIn; + // } else if (IOBaseAssetId.is(swap.assetOut)) { + // baseAssetSwapType = "out"; + // baseAssetAmount = swap.amountOut; + // baseAsset = swap.assetOut; + // } + + // if (!baseAssetSwapType || !baseAsset || !baseAssetAmount) + // return marketTotals; + + const total = marketTotals[swap.marketId]; + if (total != null) { + marketTotals[swap.marketId] = { + ...total, + baseAssetIn: swap.baseAssetIn.plus(total.baseAssetIn), + baseAssetOut: swap.baseAssetOut.plus(total.baseAssetOut), }; } else { - markets[swap.marketId] = { - baseAsset: baseAsset, - baseAssetIn: - baseAssetSwapType === "in" ? baseAssetAmount : new Decimal(0), - baseAssetOut: - baseAssetSwapType === "out" ? baseAssetAmount : new Decimal(0), + marketTotals[swap.marketId] = { + // baseAsset: baseAsset, + baseAssetIn: swap.baseAssetIn, + baseAssetOut: swap.baseAssetOut, }; } - return markets; + return marketTotals; }, {}); return { ...traders, [accountId]: marketTotal }; @@ -344,7 +371,7 @@ export async function getStaticProps() { marketsSummary.push({ question: market.question!, marketId: market.marketId, - baseAssetId: marketTotal.baseAsset, + baseAssetId: parseAssetIdString(market.baseAsset) as BaseAssetId, profit: diff.div(ZTG).toNumber(), }); @@ -406,7 +433,7 @@ export async function getStaticProps() { const Leaderboard: NextPage<{ rankings: Rank[]; }> = ({ rankings }) => { - console.log(rankings[0].markets); + // console.log(rankings[0].markets); return (
Most Profit
From bccf00e91b8898e16040401a97729505ee5edad7 Mon Sep 17 00:00:00 2001 From: Tom Robiquet Date: Thu, 22 Jun 2023 12:47:23 +0300 Subject: [PATCH 17/40] event mapping and debug --- pages/leaderboard.tsx | 71 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 56 insertions(+), 15 deletions(-) diff --git a/pages/leaderboard.tsx b/pages/leaderboard.tsx index c2a6b1305..6f23e6a86 100644 --- a/pages/leaderboard.tsx +++ b/pages/leaderboard.tsx @@ -1,9 +1,7 @@ import { - AssetId, BaseAssetId, create, getMarketIdOf, - IOBaseAssetId, IOForeignAssetId, IOMarketOutcomeAssetId, parseAssetId, @@ -44,7 +42,7 @@ type Trade = { baseAssetOut: Decimal; // assetIn?: AssetId; // assetOut?: AssetId; - type: "trade" | "redeem" | "sellFullSet" | "buyFullSet"; + // type: "trade" | "redeem" | "sellFullSet" | "buyFullSet"; }; type AccountId = string; @@ -105,7 +103,7 @@ type Event = { const convertEventToTrade = (event: Event) => { const assetId = parseAssetId(event.assetId).unwrap(); - + console.log(event.event); const marketId = IOMarketOutcomeAssetId.is(assetId) ? getMarketIdOf(assetId) : undefined; @@ -118,12 +116,34 @@ const convertEventToTrade = (event: Event) => { // assetOut: { Ztg: null }, baseAssetIn: new Decimal(0), baseAssetOut: new Decimal(event.dBalance).abs(), - type: "redeem", + // type: "redeem", }; return trade; } else if (event.event === "SoldCompleteSet") { - } else if (event.event === "Deposited") { - } else if (event.event === "BoughtCompleteSet") { + const trade: Trade = { + marketId, + // assetIn: assetId, + // assetOut: { Ztg: null }, + baseAssetIn: new Decimal(0), + baseAssetOut: new Decimal(event.dBalance).abs(), + // type: "redeem", + }; + return trade; + } else if ( + event.event === "Deposited" || + event.event === "DepositedEndowed" || + event.event === "EndowedBoughtCompleteSet" || + event.event === "BoughtCompleteSet" + ) { + const trade: Trade = { + marketId, + // assetIn: assetId, + // assetOut: { Ztg: null }, + baseAssetIn: new Decimal(event.dBalance).abs(), + baseAssetOut: new Decimal(0), + // type: "redeem", + }; + return trade; } } }; @@ -201,7 +221,7 @@ export async function getStaticProps() { // }, {}); const { historicalSwaps } = await sdk.indexer.historicalSwaps({ where: { - // accountId_eq: "dDywmamjrDkaT18ybCRJBfax65CoxJNSWGZfwiQrbkAe95wq3", + accountId_eq: "dE1CBAKzrE1C9R6NkgdEUNgv1H9x4xgT39wzSnxCtX3FpSqS8", }, }); // console.log(historicalSwaps); @@ -238,7 +258,7 @@ export async function getStaticProps() { baseAssetSwapType === "out" ? new Decimal(swap.assetAmountOut) : new Decimal(0), - type: "trade", + // type: "trade", }; if (trades) { @@ -259,12 +279,14 @@ export async function getStaticProps() { const { historicalAccountBalances: buyFullSetEvents } = await sdk.indexer.historicalAccountBalances({ where: { - AND: [ + OR: [ { event_contains: "BoughtComplete", }, { - OR: [{ event_contains: "Deposited", assetId_not_contains: "pool" }], + AND: [ + { event_contains: "Deposited", assetId_not_contains: "pool" }, + ], }, ], }, @@ -278,14 +300,23 @@ export async function getStaticProps() { }); console.time("t"); - const fullSetEvents = [...buyFullSetEvents, ...sellFullSetEvents]; + const fullSetEvents = [ + ...buyFullSetEvents, + + // ...sellFullSetEvents + ]; + console.log(fullSetEvents); const uniqueFullSetEvents = fullSetEvents.reduce( (uniqueEvents, event) => { + console.log("event", event); + const duplicateEvent = uniqueEvents.find( (entry) => entry.id === event.id, ); + console.log("duplicateEvent", duplicateEvent); + if (!duplicateEvent) { uniqueEvents.push(event); } @@ -367,6 +398,10 @@ export async function getStaticProps() { if (market?.status === "Resolved") { const diff = marketTotal.baseAssetOut.minus(marketTotal.baseAssetIn); + console.log("marketId:", marketId); + console.log("diff", diff.div(ZTG).toString()); + // console.log(marketTotal.baseAssetOut.div(ZTG).toString()); + // console.log(marketTotal.baseAssetIn.div(ZTG).toString()); marketsSummary.push({ question: market.question!, @@ -382,6 +417,9 @@ export async function getStaticProps() { marketTotal.baseAsset, endTimestamp, ); + + console.log("usdprice", marketEndBaseAssetPrice?.toFixed(2)); + const usdProfitLoss = diff.mul(marketEndBaseAssetPrice); return total.plus(usdProfitLoss); } else { @@ -409,7 +447,8 @@ export async function getStaticProps() { }, []) .sort((a, b) => b.profit - a.profit); - const top10 = rankings.slice(0, 100); + const top10 = rankings; + // .slice(0, 100); const indentities = await Promise.all( top10.map((player) => sdk.api.query.identity.identityOf(player.accountId)), @@ -454,10 +493,12 @@ const Leaderboard: NextPage<{
{rank.markets .sort((a, b) => b.profit - a.profit) - .slice(0, 20) // todo move this server side + // .slice(0, 1000) // todo move this server side .map((market) => (
-
{market.question}
+
+ {market.question}-{market.marketId} +
{formatNumberCompact(market.profit)}{" "} {lookupAssetSymbol(market.baseAssetId)} From 22462e3774d1d1e0e5b712fad4b9090c61fdfe31 Mon Sep 17 00:00:00 2001 From: Tom Robiquet Date: Thu, 6 Jul 2023 12:01:58 +0200 Subject: [PATCH 18/40] upgrade --- package.json | 2 +- yarn.lock | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index a9de6bcfc..80330bbdc 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "@zeitgeistpm/avatara-react": "^1.3.2", "@zeitgeistpm/avatara-util": "^1.2.0", "@zeitgeistpm/sdk": "^1.0.3", - "@zeitgeistpm/sdk-next": "npm:@zeitgeistpm/sdk@2.29.20", + "@zeitgeistpm/sdk-next": "npm:@zeitgeistpm/sdk@2.29.21", "@zeitgeistpm/utility": "^2.18.12", "axios": "^0.21.4", "boring-avatars": "^1.6.1", diff --git a/yarn.lock b/yarn.lock index 987171aa9..8029394c9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3082,14 +3082,14 @@ __metadata: languageName: node linkType: hard -"@zeitgeistpm/indexer@npm:^3.0.13": - version: 3.0.13 - resolution: "@zeitgeistpm/indexer@npm:3.0.13" +"@zeitgeistpm/indexer@npm:^3.0.14": + version: 3.0.14 + resolution: "@zeitgeistpm/indexer@npm:3.0.14" dependencies: graphql: ^16.6.0 graphql-request: ^5.0.0 graphql-tag: ^2.12.6 - checksum: d27deb572e1a4aca88493724b5f53b3ad4dc2722c5538e0043f6dc0af8ab9a8622a5e84960fd4810c500e267e26bb57d06d8259e05efe39474df761e2f556207 + checksum: a8f0b65cfc3d563f2f96bb4f2c1257466e7ca1873c136e6fcc350f37829189602958c20394ea8ad84cb1eb09f8acfa17e62279d77b44052f1f46a391e89f22c5 languageName: node linkType: hard @@ -3107,12 +3107,12 @@ __metadata: languageName: node linkType: hard -"@zeitgeistpm/sdk-next@npm:@zeitgeistpm/sdk@2.29.20": - version: 2.29.20 - resolution: "@zeitgeistpm/sdk@npm:2.29.20" +"@zeitgeistpm/sdk-next@npm:@zeitgeistpm/sdk@2.29.21": + version: 2.29.21 + resolution: "@zeitgeistpm/sdk@npm:2.29.21" dependencies: "@zeitgeistpm/augment-api": ^2.11.5 - "@zeitgeistpm/indexer": ^3.0.13 + "@zeitgeistpm/indexer": ^3.0.14 "@zeitgeistpm/rpc": ^2.7.6 "@zeitgeistpm/utility": ^2.18.13 "@zeitgeistpm/web3.storage": ^2.9.13 @@ -3128,7 +3128,7 @@ __metadata: "@polkadot/api": "*" "@polkadot/types": "*" "@polkadot/util": "*" - checksum: c3d986c074e7543efd718a86a02d8c1ea53c083c54ff4ccd48c7873b709c5315ca90b43c0d3584525749e270fa1475e8745a5de7451bd946960a8baa984b335e + checksum: 5e8f28d9fde6c22cfcf67e86661600b1447b31f19471b8ddd238e8c36d68c5d132d4490abd46f1e7db427b9fab04800d46bacbb33e3e052ad350f65b76e6ad3c languageName: node linkType: hard @@ -3227,7 +3227,7 @@ __metadata: "@zeitgeistpm/avatara-react": ^1.3.2 "@zeitgeistpm/avatara-util": ^1.2.0 "@zeitgeistpm/sdk": ^1.0.3 - "@zeitgeistpm/sdk-next": "npm:@zeitgeistpm/sdk@2.29.20" + "@zeitgeistpm/sdk-next": "npm:@zeitgeistpm/sdk@2.29.21" "@zeitgeistpm/utility": ^2.18.12 autoprefixer: 10.2.5 axios: ^0.21.4 From 1ab41cf97c0134c4d8c483efac6d96b8659ff2d2 Mon Sep 17 00:00:00 2001 From: Tom Robiquet Date: Thu, 6 Jul 2023 14:12:27 +0200 Subject: [PATCH 19/40] enable link --- components/menu/index.tsx | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/components/menu/index.tsx b/components/menu/index.tsx index 015099b9f..3b64a69a7 100644 --- a/components/menu/index.tsx +++ b/components/menu/index.tsx @@ -106,22 +106,15 @@ const TopBar = () => {
{({ active }) => ( - { - event.preventDefault(); - close(); - }} - > + @@ -155,17 +148,13 @@ const TopBar = () => { { - event.preventDefault(); - }} > -
+
-
Leaderboard (coming soon)
+
Leaderboard
From 0198394e70bd07ea0ffd3763c280aef339a0e21a Mon Sep 17 00:00:00 2001 From: Tom Robiquet Date: Thu, 6 Jul 2023 16:32:34 +0200 Subject: [PATCH 20/40] fix duplication detection --- pages/leaderboard.tsx | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/pages/leaderboard.tsx b/pages/leaderboard.tsx index 6f23e6a86..58bf644ce 100644 --- a/pages/leaderboard.tsx +++ b/pages/leaderboard.tsx @@ -99,6 +99,10 @@ type Event = { event: string; id: string; timestamp: any; + extrinsic?: { + hash: string; + name: string; + }; }; const convertEventToTrade = (event: Event) => { @@ -221,7 +225,9 @@ export async function getStaticProps() { // }, {}); const { historicalSwaps } = await sdk.indexer.historicalSwaps({ where: { - accountId_eq: "dE1CBAKzrE1C9R6NkgdEUNgv1H9x4xgT39wzSnxCtX3FpSqS8", + // accountId_eq: "dE1CBAKzrE1C9R6NkgdEUNgv1H9x4xgT39wzSnxCtX3FpSqS8", //old ac + // accountId_eq: "dE3zfJtCC2YMHjgSifTbJg98EqhiVFeXvA8VCnCqyNty4ZYvv", //new ac creator + // accountId_eq: "dDyQQkwy5MmibHv5y1qQYpADS6x2x8yJjzaTRt2uTGfeSD7V9", //new ac lp }, }); // console.log(historicalSwaps); @@ -312,7 +318,7 @@ export async function getStaticProps() { console.log("event", event); const duplicateEvent = uniqueEvents.find( - (entry) => entry.id === event.id, + (entry) => entry.extrinsic?.hash === event.extrinsic?.hash, ); console.log("duplicateEvent", duplicateEvent); @@ -340,6 +346,8 @@ export async function getStaticProps() { } }); + console.log(tradersWithSwaps); + //loop through accounts and trades, total up baseAsset in and out for each market const tradersAggregatedByMarket = Object.keys( tradersWithSwaps, @@ -385,6 +393,8 @@ export async function getStaticProps() { return { ...traders, [accountId]: marketTotal }; }, {}); + console.log(tradersAggregatedByMarket); + const tradeProfits = Object.keys( tradersAggregatedByMarket, ).reduce((ranks, accountId) => { From 13e5dd84deed2946dcc7748adc74ec3a4d19f6ad Mon Sep 17 00:00:00 2001 From: Tom Robiquet Date: Thu, 6 Jul 2023 16:58:49 +0200 Subject: [PATCH 21/40] adjust styling and types --- pages/leaderboard.tsx | 70 ++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/pages/leaderboard.tsx b/pages/leaderboard.tsx index 58bf644ce..781dd2a20 100644 --- a/pages/leaderboard.tsx +++ b/pages/leaderboard.tsx @@ -23,6 +23,7 @@ import Link from "next/link"; import Avatar from "components/ui/Avatar"; import { formatNumberCompact } from "lib/util/format-compact"; import { parseAssetIdString } from "lib/util/parse-asset-id"; +import { FullHistoricalAccountBalanceFragment } from "@zeitgeistpm/indexer"; //todo: // include buy/sell full set events @@ -91,21 +92,21 @@ type Rank = { type BasePrices = { [key: string | "ztg"]: [number, number][]; }; -type Event = { - accountId: string; - assetId: string; - blockNumber: number; - dBalance: any; - event: string; - id: string; - timestamp: any; - extrinsic?: { - hash: string; - name: string; - }; -}; - -const convertEventToTrade = (event: Event) => { +// type Event = { +// accountId: string; +// assetId: string; +// blockNumber: number; +// dBalance: any; +// event: string; +// id: string; +// timestamp: any; +// extrinsic?: { +// hash: string; +// name: string; +// }; +// }; + +const convertEventToTrade = (event: FullHistoricalAccountBalanceFragment) => { const assetId = parseAssetId(event.assetId).unwrap(); console.log(event.event); const marketId = IOMarketOutcomeAssetId.is(assetId) @@ -313,24 +314,23 @@ export async function getStaticProps() { ]; console.log(fullSetEvents); - const uniqueFullSetEvents = fullSetEvents.reduce( - (uniqueEvents, event) => { - console.log("event", event); + const uniqueFullSetEvents = fullSetEvents.reduce< + FullHistoricalAccountBalanceFragment[] + >((uniqueEvents, event) => { + console.log("event", event); - const duplicateEvent = uniqueEvents.find( - (entry) => entry.extrinsic?.hash === event.extrinsic?.hash, - ); + const duplicateEvent = uniqueEvents.find( + (entry) => entry.extrinsic?.hash === event.extrinsic?.hash, + ); - console.log("duplicateEvent", duplicateEvent); + console.log("duplicateEvent", duplicateEvent); - if (!duplicateEvent) { - uniqueEvents.push(event); - } + if (!duplicateEvent) { + uniqueEvents.push(event); + } - return uniqueEvents; - }, - [], - ); + return uniqueEvents; + }, []); console.log(uniqueFullSetEvents); [...redeemEvents, ...uniqueFullSetEvents].forEach((event) => { @@ -485,10 +485,12 @@ const Leaderboard: NextPage<{ // console.log(rankings[0].markets); return (
-
Most Profit
-
+
+ Most Profitable Traders +
+
{rankings.map((rank, index) => ( -
+
{index + 1}
${rank.profit.toFixed(0)}
-
+ {/*
{rank.markets .sort((a, b) => b.profit - a.profit) // .slice(0, 1000) // todo move this server side @@ -515,7 +517,7 @@ const Leaderboard: NextPage<{
))} -
+
*/}
))}
From f0c414e04497636e2a7ab4c8a98d0526d1bc50fa Mon Sep 17 00:00:00 2001 From: Tom Robiquet Date: Thu, 6 Jul 2023 18:02:08 +0200 Subject: [PATCH 22/40] mobile styling --- pages/leaderboard.tsx | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/pages/leaderboard.tsx b/pages/leaderboard.tsx index 781dd2a20..d606bae37 100644 --- a/pages/leaderboard.tsx +++ b/pages/leaderboard.tsx @@ -457,11 +457,10 @@ export async function getStaticProps() { }, []) .sort((a, b) => b.profit - a.profit); - const top10 = rankings; - // .slice(0, 100); + const top20 = rankings.slice(0, 20); const indentities = await Promise.all( - top10.map((player) => sdk.api.query.identity.identityOf(player.accountId)), + top20.map((player) => sdk.api.query.identity.identityOf(player.accountId)), ); const names: (string | undefined)[] = indentities.map( @@ -470,7 +469,7 @@ export async function getStaticProps() { return { props: { - rankings: top10.map((player, index) => ({ + rankings: top20.map((player, index) => ({ ...player, name: names[index] ?? null, })), @@ -484,23 +483,29 @@ const Leaderboard: NextPage<{ }> = ({ rankings }) => { // console.log(rankings[0].markets); return ( -
+
Most Profitable Traders
{rankings.map((rank, index) => ( -
+
-
{index + 1}
+
+ {index + 1} +
+
+ +
- - {rank.name ?? rank.accountId} + {rank.name ?? rank.accountId} -
${rank.profit.toFixed(0)}
+
+ ${rank.profit.toFixed(0)} +
{/*
{rank.markets From bf8bfb0662242860547fbbab69b045106b1ce8f8 Mon Sep 17 00:00:00 2001 From: Tom Robiquet Date: Fri, 7 Jul 2023 10:45:37 +0200 Subject: [PATCH 23/40] include sell full sets --- pages/leaderboard.tsx | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/pages/leaderboard.tsx b/pages/leaderboard.tsx index d606bae37..b49621f75 100644 --- a/pages/leaderboard.tsx +++ b/pages/leaderboard.tsx @@ -26,8 +26,7 @@ import { parseAssetIdString } from "lib/util/parse-asset-id"; import { FullHistoricalAccountBalanceFragment } from "@zeitgeistpm/indexer"; //todo: -// include buy/sell full set events -// styling +// handle scalar market redeems // Track trades, buy full set, sell full set, @@ -106,7 +105,11 @@ type BasePrices = { // }; // }; -const convertEventToTrade = (event: FullHistoricalAccountBalanceFragment) => { +const convertEventToTrade = ( + event: FullHistoricalAccountBalanceFragment, + longTokenVaue?: Decimal, + shortTokenVaue?: Decimal, +) => { const assetId = parseAssetId(event.assetId).unwrap(); console.log(event.event); const marketId = IOMarketOutcomeAssetId.is(assetId) @@ -115,6 +118,7 @@ const convertEventToTrade = (event: FullHistoricalAccountBalanceFragment) => { if (marketId !== undefined) { if (event.event === "TokensRedeemed") { + //todo if scalar need to calcvalues const trade: Trade = { marketId, // assetIn: assetId, @@ -228,7 +232,7 @@ export async function getStaticProps() { where: { // accountId_eq: "dE1CBAKzrE1C9R6NkgdEUNgv1H9x4xgT39wzSnxCtX3FpSqS8", //old ac // accountId_eq: "dE3zfJtCC2YMHjgSifTbJg98EqhiVFeXvA8VCnCqyNty4ZYvv", //new ac creator - // accountId_eq: "dDyQQkwy5MmibHv5y1qQYpADS6x2x8yJjzaTRt2uTGfeSD7V9", //new ac lp + accountId_eq: "dDyQQkwy5MmibHv5y1qQYpADS6x2x8yJjzaTRt2uTGfeSD7V9", //new ac lp }, }); // console.log(historicalSwaps); @@ -307,11 +311,7 @@ export async function getStaticProps() { }); console.time("t"); - const fullSetEvents = [ - ...buyFullSetEvents, - - // ...sellFullSetEvents - ]; + const fullSetEvents = [...buyFullSetEvents, ...sellFullSetEvents]; console.log(fullSetEvents); const uniqueFullSetEvents = fullSetEvents.reduce< @@ -507,22 +507,22 @@ const Leaderboard: NextPage<{ ${rank.profit.toFixed(0)}
- {/*
+
{rank.markets .sort((a, b) => b.profit - a.profit) // .slice(0, 1000) // todo move this server side .map((market) => (
-
+ {market.question}-{market.marketId} -
+
{formatNumberCompact(market.profit)}{" "} {lookupAssetSymbol(market.baseAssetId)}
))} -
*/} +
))}
From 0a83a329f14696db9e148b3d8a4fa5f8ed2a3f51 Mon Sep 17 00:00:00 2001 From: Tom Robiquet Date: Fri, 7 Jul 2023 11:06:36 +0200 Subject: [PATCH 24/40] handle scalar redeems --- pages/leaderboard.tsx | 47 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/pages/leaderboard.tsx b/pages/leaderboard.tsx index b49621f75..17543fa5b 100644 --- a/pages/leaderboard.tsx +++ b/pages/leaderboard.tsx @@ -2,8 +2,10 @@ import { BaseAssetId, create, getMarketIdOf, + getScalarIndexOf, IOForeignAssetId, IOMarketOutcomeAssetId, + IOScalarAssetId, parseAssetId, ZeitgeistIpfs, } from "@zeitgeistpm/sdk-next"; @@ -24,6 +26,10 @@ import Avatar from "components/ui/Avatar"; import { formatNumberCompact } from "lib/util/format-compact"; import { parseAssetIdString } from "lib/util/parse-asset-id"; import { FullHistoricalAccountBalanceFragment } from "@zeitgeistpm/indexer"; +import { + calcScalarWinnings, + calcScalarResolvedPrices, +} from "lib/util/calc-scalar-winnings"; //todo: // handle scalar market redeems @@ -119,12 +125,17 @@ const convertEventToTrade = ( if (marketId !== undefined) { if (event.event === "TokensRedeemed") { //todo if scalar need to calcvalues + const assetValue = IOScalarAssetId.is(assetId) + ? getScalarIndexOf(assetId) === 0 + ? shortTokenVaue + : longTokenVaue + : new Decimal(1); const trade: Trade = { marketId, // assetIn: assetId, // assetOut: { Ztg: null }, baseAssetIn: new Decimal(0), - baseAssetOut: new Decimal(event.dBalance).abs(), + baseAssetOut: new Decimal(event.dBalance).mul(assetValue ?? 1).abs(), // type: "redeem", }; return trade; @@ -333,7 +344,7 @@ export async function getStaticProps() { }, []); console.log(uniqueFullSetEvents); - [...redeemEvents, ...uniqueFullSetEvents].forEach((event) => { + [...uniqueFullSetEvents].forEach((event) => { const trades = tradersWithSwaps[event.accountId]; // probably this check is needed as accounts can aquire tokens via buy full sell or transfer @@ -346,6 +357,38 @@ export async function getStaticProps() { } }); + [...redeemEvents].forEach((event) => { + const trades = tradersWithSwaps[event.accountId]; + + const assetId = parseAssetIdString(event.assetId); + + const market = IOMarketOutcomeAssetId.is(assetId) + ? markets.find((m) => m.marketId === Number(getMarketIdOf(assetId))) + : null; + if (trades && market) { + const values = + market.marketType.scalar?.[0] != null && + market.marketType.scalar[1] != null && + market.resolvedOutcome != null + ? calcScalarResolvedPrices( + new Decimal(market.marketType.scalar[0]), + new Decimal(market.marketType.scalar[1]), + new Decimal(market.resolvedOutcome), + ) + : { longTokenValue: undefined, shortTokenValue: undefined }; + + const trade = convertEventToTrade( + event, + values.longTokenValue, + values.shortTokenValue, + ); + + if (trade) trades.push(trade); + + tradersWithSwaps[event.accountId] = trades; + } + }); + console.log(tradersWithSwaps); //loop through accounts and trades, total up baseAsset in and out for each market From b032278b5ac54c2355fafa9ae11f81d7ebc7e9b4 Mon Sep 17 00:00:00 2001 From: Tom Robiquet Date: Fri, 7 Jul 2023 11:34:12 +0200 Subject: [PATCH 25/40] fix scalar winnings bug and add tests --- lib/util/calc-scalar-winnings.spec.ts | 39 ++++++++++++++++++++++++++- lib/util/calc-scalar-winnings.ts | 16 +++++++++-- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/lib/util/calc-scalar-winnings.spec.ts b/lib/util/calc-scalar-winnings.spec.ts index 26aafa53e..ee3f73e0b 100644 --- a/lib/util/calc-scalar-winnings.spec.ts +++ b/lib/util/calc-scalar-winnings.spec.ts @@ -1,16 +1,53 @@ -import { calcScalarWinnings } from "./calc-scalar-winnings"; +import { + calcScalarResolvedPrices, + calcScalarWinnings, +} from "./calc-scalar-winnings"; describe("calcScalarWinnings", () => { test("should calculate winnings correctly for short tokens", () => { const winnings = calcScalarWinnings(0, 10, 5, 100, 0); expect(winnings.toNumber()).toEqual(50); }); + test("should calculate winnings correctly for long tokens", () => { const winnings = calcScalarWinnings(0, 40, 10, 0, 100); expect(winnings.toNumber()).toEqual(25); }); + test("should calculate winnings correctly for both long and short tokens", () => { const winnings = calcScalarWinnings(0, 40, 10, 100, 100); expect(winnings.toNumber()).toEqual(100); }); + + test("long value should be capped at 1 if resolved outcome is outside of bounds", () => { + const { longTokenValue } = calcScalarResolvedPrices(0, 40, 50); + expect(longTokenValue.toNumber()).toEqual(1); + }); + + test("long value should not fall below 0 if resolved outcome is outside of bounds", () => { + const { longTokenValue } = calcScalarResolvedPrices(10, 40, 0); + expect(longTokenValue.toNumber()).toEqual(0); + }); + + test("short value should not fall below 0 if resolved outcome is outside of bounds", () => { + const { shortTokenValue } = calcScalarResolvedPrices(0, 40, 50); + expect(shortTokenValue.toNumber()).toEqual(0); + }); + + test("short value should be capped at 1 resolved outcome is outside of bounds", () => { + const { shortTokenValue } = calcScalarResolvedPrices(10, 40, 0); + expect(shortTokenValue.toNumber()).toEqual(1); + }); + + describe("getScalarIndexOf integration", () => { + // test("should return 1 for short", () => { + // const index = getScalarIndexOf({ + // ScalarOutcome: [1 as MarketId, "Short"], + // }); + + // expect(index).toEqual(1); + // }); + + test("should return 0 for long", () => {}); + }); }); diff --git a/lib/util/calc-scalar-winnings.ts b/lib/util/calc-scalar-winnings.ts index d26d4853c..487c644ce 100644 --- a/lib/util/calc-scalar-winnings.ts +++ b/lib/util/calc-scalar-winnings.ts @@ -31,8 +31,20 @@ export const calcScalarResolvedPrices = ( .minus(lowerBound) .div(priceRange); - const longTokenValue = resolvedNumberAsPercentage; - const shortTokenValue = new Decimal(1).minus(resolvedNumberAsPercentage); + const longTokenValue = constrainValue(resolvedNumberAsPercentage); + const shortTokenValue = constrainValue( + new Decimal(1).minus(resolvedNumberAsPercentage), + ); return { longTokenValue, shortTokenValue }; }; + +const constrainValue = (value: Decimal): Decimal => { + if (value.greaterThan(1)) { + return new Decimal(1); + } else if (value.lessThan(0)) { + return new Decimal(0); + } else { + return value; + } +}; From 44b106b0fc4ae81ad09b6725636c37d6bf6c4f97 Mon Sep 17 00:00:00 2001 From: Tom Robiquet Date: Fri, 7 Jul 2023 11:36:50 +0200 Subject: [PATCH 26/40] fix scalar redeems --- pages/leaderboard.tsx | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/pages/leaderboard.tsx b/pages/leaderboard.tsx index 17543fa5b..423f635db 100644 --- a/pages/leaderboard.tsx +++ b/pages/leaderboard.tsx @@ -117,16 +117,21 @@ const convertEventToTrade = ( shortTokenVaue?: Decimal, ) => { const assetId = parseAssetId(event.assetId).unwrap(); - console.log(event.event); const marketId = IOMarketOutcomeAssetId.is(assetId) ? getMarketIdOf(assetId) : undefined; if (marketId !== undefined) { if (event.event === "TokensRedeemed") { + console.log("redeemed", marketId); + + console.log(shortTokenVaue, longTokenVaue); + console.log(IOScalarAssetId.is(assetId) && getScalarIndexOf(assetId)); + console.log(assetId); + //todo if scalar need to calcvalues const assetValue = IOScalarAssetId.is(assetId) - ? getScalarIndexOf(assetId) === 0 + ? getScalarIndexOf(assetId) === 1 ? shortTokenVaue : longTokenVaue : new Decimal(1); @@ -138,6 +143,10 @@ const convertEventToTrade = ( baseAssetOut: new Decimal(event.dBalance).mul(assetValue ?? 1).abs(), // type: "redeem", }; + + console.log("value", assetValue); + console.log("balance", event.dBalance); + return trade; } else if (event.event === "SoldCompleteSet") { const trade: Trade = { @@ -243,7 +252,8 @@ export async function getStaticProps() { where: { // accountId_eq: "dE1CBAKzrE1C9R6NkgdEUNgv1H9x4xgT39wzSnxCtX3FpSqS8", //old ac // accountId_eq: "dE3zfJtCC2YMHjgSifTbJg98EqhiVFeXvA8VCnCqyNty4ZYvv", //new ac creator - accountId_eq: "dDyQQkwy5MmibHv5y1qQYpADS6x2x8yJjzaTRt2uTGfeSD7V9", //new ac lp + // accountId_eq: "dDyQQkwy5MmibHv5y1qQYpADS6x2x8yJjzaTRt2uTGfeSD7V9", //new ac lp + // accountId_eq: "dDywmamjrDkaT18ybCRJBfax65CoxJNSWGZfwiQrbkAe95wq3", }, }); // console.log(historicalSwaps); @@ -451,8 +461,8 @@ export async function getStaticProps() { if (market?.status === "Resolved") { const diff = marketTotal.baseAssetOut.minus(marketTotal.baseAssetIn); - console.log("marketId:", marketId); - console.log("diff", diff.div(ZTG).toString()); + // console.log("marketId:", marketId); + // console.log("diff", diff.div(ZTG).toString()); // console.log(marketTotal.baseAssetOut.div(ZTG).toString()); // console.log(marketTotal.baseAssetIn.div(ZTG).toString()); @@ -471,7 +481,7 @@ export async function getStaticProps() { endTimestamp, ); - console.log("usdprice", marketEndBaseAssetPrice?.toFixed(2)); + // console.log("usdprice", marketEndBaseAssetPrice?.toFixed(2)); const usdProfitLoss = diff.mul(marketEndBaseAssetPrice); return total.plus(usdProfitLoss); @@ -500,7 +510,8 @@ export async function getStaticProps() { }, []) .sort((a, b) => b.profit - a.profit); - const top20 = rankings.slice(0, 20); + const top20 = rankings; + // .slice(0, 20); const indentities = await Promise.all( top20.map((player) => sdk.api.query.identity.identityOf(player.accountId)), From dd603a3c5763457f4c3ad8296ea10a4df7ee2462 Mon Sep 17 00:00:00 2001 From: Tom Robiquet Date: Fri, 7 Jul 2023 12:43:43 +0200 Subject: [PATCH 27/40] fix price lookup, void suspicious markets --- pages/leaderboard.tsx | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/pages/leaderboard.tsx b/pages/leaderboard.tsx index 423f635db..2837144ca 100644 --- a/pages/leaderboard.tsx +++ b/pages/leaderboard.tsx @@ -26,13 +26,10 @@ import Avatar from "components/ui/Avatar"; import { formatNumberCompact } from "lib/util/format-compact"; import { parseAssetIdString } from "lib/util/parse-asset-id"; import { FullHistoricalAccountBalanceFragment } from "@zeitgeistpm/indexer"; -import { - calcScalarWinnings, - calcScalarResolvedPrices, -} from "lib/util/calc-scalar-winnings"; +import { calcScalarResolvedPrices } from "lib/util/calc-scalar-winnings"; //todo: -// handle scalar market redeems +// when base asset in is 0 void market // Track trades, buy full set, sell full set, @@ -82,14 +79,14 @@ type MarketSummary = { type TradersSummary = { [key: AccountId]: { - profit: number; + profitUsd: number; markets: MarketSummary[]; }; }; type Rank = { accountId: string; - profit: number; + profitUsd: number; name?: string; markets: MarketSummary[]; }; @@ -254,6 +251,8 @@ export async function getStaticProps() { // accountId_eq: "dE3zfJtCC2YMHjgSifTbJg98EqhiVFeXvA8VCnCqyNty4ZYvv", //new ac creator // accountId_eq: "dDyQQkwy5MmibHv5y1qQYpADS6x2x8yJjzaTRt2uTGfeSD7V9", //new ac lp // accountId_eq: "dDywmamjrDkaT18ybCRJBfax65CoxJNSWGZfwiQrbkAe95wq3", + // accountId_eq: "dDyDMpv3YqFYdDmhqEdq8ZYnPU4gfXMSjqK6375CmTYF2Jt5W", + // accountId_eq: "dDyQQkwy5MmibHv5y1qQYpADS6x2x8yJjzaTRt2uTGfeSD7V9", }, }); // console.log(historicalSwaps); @@ -446,7 +445,7 @@ export async function getStaticProps() { return { ...traders, [accountId]: marketTotal }; }, {}); - console.log(tradersAggregatedByMarket); + console.log("tradersAggregatedByMarket", tradersAggregatedByMarket); const tradeProfits = Object.keys( tradersAggregatedByMarket, @@ -455,11 +454,14 @@ export async function getStaticProps() { const marketsSummary: MarketSummary[] = []; const profit = Object.keys(trader).reduce((total, marketId) => { - const marketTotal = trader[marketId]; + const marketTotal: MarketBaseDetails = trader[marketId]; + console.log("marketTotal", marketTotal); const market = markets.find((m) => m.marketId === Number(marketId)); - if (market?.status === "Resolved") { + const suspiciousActivity = marketTotal.baseAssetIn.eq(0); + + if (market?.status === "Resolved" && !suspiciousActivity) { const diff = marketTotal.baseAssetOut.minus(marketTotal.baseAssetIn); // console.log("marketId:", marketId); // console.log("diff", diff.div(ZTG).toString()); @@ -477,13 +479,14 @@ export async function getStaticProps() { const marketEndBaseAssetPrice = lookupPrice( basePrices, - marketTotal.baseAsset, + parseAssetIdString(market.baseAsset) as BaseAssetId, endTimestamp, ); // console.log("usdprice", marketEndBaseAssetPrice?.toFixed(2)); + console.log(marketEndBaseAssetPrice); - const usdProfitLoss = diff.mul(marketEndBaseAssetPrice); + const usdProfitLoss = diff.mul(marketEndBaseAssetPrice ?? 0); return total.plus(usdProfitLoss); } else { return total; @@ -493,22 +496,24 @@ export async function getStaticProps() { return { ...ranks, [accountId]: { - profit: profit.div(ZTG).toNumber(), + profitUsd: profit.div(ZTG).toNumber(), markets: marketsSummary, }, }; }, {}); + console.log("tradeProfits", tradeProfits); + const rankings = Object.keys(tradeProfits) .reduce((rankings, accountId) => { rankings.push({ accountId, - profit: tradeProfits[accountId].profit, + profitUsd: tradeProfits[accountId].profitUsd, markets: tradeProfits[accountId].markets, }); return rankings; }, []) - .sort((a, b) => b.profit - a.profit); + .sort((a, b) => b.profitUsd - a.profitUsd); const top20 = rankings; // .slice(0, 20); @@ -558,10 +563,10 @@ const Leaderboard: NextPage<{ {rank.name ?? rank.accountId}
- ${rank.profit.toFixed(0)} + ${rank.profitUsd.toFixed(0)}
-
+ {/*
{rank.markets .sort((a, b) => b.profit - a.profit) // .slice(0, 1000) // todo move this server side @@ -576,7 +581,7 @@ const Leaderboard: NextPage<{
))} -
+
*/}
))}
From dc7410287490c62800cfa3236b3ce605e93a2a75 Mon Sep 17 00:00:00 2001 From: Tom Robiquet Date: Fri, 7 Jul 2023 13:23:01 +0200 Subject: [PATCH 28/40] clean up --- pages/leaderboard.tsx | 107 +++--------------------------------------- 1 file changed, 6 insertions(+), 101 deletions(-) diff --git a/pages/leaderboard.tsx b/pages/leaderboard.tsx index 2837144ca..7e4be8425 100644 --- a/pages/leaderboard.tsx +++ b/pages/leaderboard.tsx @@ -28,24 +28,14 @@ import { parseAssetIdString } from "lib/util/parse-asset-id"; import { FullHistoricalAccountBalanceFragment } from "@zeitgeistpm/indexer"; import { calcScalarResolvedPrices } from "lib/util/calc-scalar-winnings"; -//todo: -// when base asset in is 0 void market - -// Track trades, buy full set, sell full set, - -// Buy Full Set events -// Deposited includes all assets -// DepositedEndowed includes all assets -// EndowedBoughtCompleteSet includes all assets -// BoughtCompleteSet only includes one asset +// Approach: aggregate base asset movements in an out of a market +// "In events": swaps, buy full set +// "Out events": swaps, sell full set, redeem type Trade = { marketId: number; baseAssetIn: Decimal; baseAssetOut: Decimal; - // assetIn?: AssetId; - // assetOut?: AssetId; - // type: "trade" | "redeem" | "sellFullSet" | "buyFullSet"; }; type AccountId = string; @@ -55,7 +45,6 @@ type Traders = { }; type MarketBaseDetails = { - // baseAsset: BaseAssetId; baseAssetIn: Decimal; baseAssetOut: Decimal; }; @@ -94,19 +83,6 @@ type Rank = { type BasePrices = { [key: string | "ztg"]: [number, number][]; }; -// type Event = { -// accountId: string; -// assetId: string; -// blockNumber: number; -// dBalance: any; -// event: string; -// id: string; -// timestamp: any; -// extrinsic?: { -// hash: string; -// name: string; -// }; -// }; const convertEventToTrade = ( event: FullHistoricalAccountBalanceFragment, @@ -120,13 +96,6 @@ const convertEventToTrade = ( if (marketId !== undefined) { if (event.event === "TokensRedeemed") { - console.log("redeemed", marketId); - - console.log(shortTokenVaue, longTokenVaue); - console.log(IOScalarAssetId.is(assetId) && getScalarIndexOf(assetId)); - console.log(assetId); - - //todo if scalar need to calcvalues const assetValue = IOScalarAssetId.is(assetId) ? getScalarIndexOf(assetId) === 1 ? shortTokenVaue @@ -134,25 +103,16 @@ const convertEventToTrade = ( : new Decimal(1); const trade: Trade = { marketId, - // assetIn: assetId, - // assetOut: { Ztg: null }, baseAssetIn: new Decimal(0), baseAssetOut: new Decimal(event.dBalance).mul(assetValue ?? 1).abs(), - // type: "redeem", }; - console.log("value", assetValue); - console.log("balance", event.dBalance); - return trade; } else if (event.event === "SoldCompleteSet") { const trade: Trade = { marketId, - // assetIn: assetId, - // assetOut: { Ztg: null }, baseAssetIn: new Decimal(0), baseAssetOut: new Decimal(event.dBalance).abs(), - // type: "redeem", }; return trade; } else if ( @@ -163,11 +123,8 @@ const convertEventToTrade = ( ) { const trade: Trade = { marketId, - // assetIn: assetId, - // assetOut: { Ztg: null }, baseAssetIn: new Decimal(event.dBalance).abs(), baseAssetOut: new Decimal(0), - // type: "redeem", }; return trade; } @@ -230,8 +187,6 @@ const getBaseAssetHistoricalPrices = async (): Promise => { }; export async function getStaticProps() { - // const client = new GraphQLClient(graphQlEndpoint); - // const sdk= await create(mainnet()); const sdk = await create({ provider: endpointOptions.map((e) => e.value), indexer: graphQlEndpoint, @@ -242,9 +197,6 @@ export async function getStaticProps() { const { markets } = await sdk.indexer.markets(); - // const marketsMap = markets.reduce((mMap, market) => { - // return { ...mMap, [market.marketId]: market }; - // }, {}); const { historicalSwaps } = await sdk.indexer.historicalSwaps({ where: { // accountId_eq: "dE1CBAKzrE1C9R6NkgdEUNgv1H9x4xgT39wzSnxCtX3FpSqS8", //old ac @@ -255,7 +207,6 @@ export async function getStaticProps() { // accountId_eq: "dDyQQkwy5MmibHv5y1qQYpADS6x2x8yJjzaTRt2uTGfeSD7V9", }, }); - // console.log(historicalSwaps); const tradersWithSwaps = historicalSwaps.reduce((traders, swap) => { const trades = traders[swap.accountId]; @@ -277,10 +228,6 @@ export async function getStaticProps() { const trade: Trade = { marketId, - // assetIn: assetInId, - // assetOut: assetOutId, - // amountIn: new Decimal(swap.assetAmountIn), - // amountOut: new Decimal(swap.assetAmountOut), baseAssetIn: baseAssetSwapType === "in" ? new Decimal(swap.assetAmountIn) @@ -289,7 +236,6 @@ export async function getStaticProps() { baseAssetSwapType === "out" ? new Decimal(swap.assetAmountOut) : new Decimal(0), - // type: "trade", }; if (trades) { @@ -330,30 +276,23 @@ export async function getStaticProps() { }, }); - console.time("t"); const fullSetEvents = [...buyFullSetEvents, ...sellFullSetEvents]; - console.log(fullSetEvents); const uniqueFullSetEvents = fullSetEvents.reduce< FullHistoricalAccountBalanceFragment[] >((uniqueEvents, event) => { - console.log("event", event); - const duplicateEvent = uniqueEvents.find( (entry) => entry.extrinsic?.hash === event.extrinsic?.hash, ); - console.log("duplicateEvent", duplicateEvent); - if (!duplicateEvent) { uniqueEvents.push(event); } return uniqueEvents; }, []); - console.log(uniqueFullSetEvents); - [...uniqueFullSetEvents].forEach((event) => { + uniqueFullSetEvents.forEach((event) => { const trades = tradersWithSwaps[event.accountId]; // probably this check is needed as accounts can aquire tokens via buy full sell or transfer @@ -366,7 +305,7 @@ export async function getStaticProps() { } }); - [...redeemEvents].forEach((event) => { + redeemEvents.forEach((event) => { const trades = tradersWithSwaps[event.accountId]; const assetId = parseAssetIdString(event.assetId); @@ -398,8 +337,6 @@ export async function getStaticProps() { } }); - console.log(tradersWithSwaps); - //loop through accounts and trades, total up baseAsset in and out for each market const tradersAggregatedByMarket = Object.keys( tradersWithSwaps, @@ -408,23 +345,6 @@ export async function getStaticProps() { if (!swaps) return traders; const marketTotal = swaps.reduce((marketTotals, swap) => { - // let baseAssetSwapType: "in" | "out" | undefined; - // let baseAssetAmount: Decimal | undefined; - // let baseAsset: BaseAssetId | undefined; - - // if (IOBaseAssetId.is(swap.assetIn)) { - // baseAssetSwapType = "in"; - // baseAssetAmount = swap.amountIn; - // baseAsset = swap.assetIn; - // } else if (IOBaseAssetId.is(swap.assetOut)) { - // baseAssetSwapType = "out"; - // baseAssetAmount = swap.amountOut; - // baseAsset = swap.assetOut; - // } - - // if (!baseAssetSwapType || !baseAsset || !baseAssetAmount) - // return marketTotals; - const total = marketTotals[swap.marketId]; if (total != null) { marketTotals[swap.marketId] = { @@ -434,7 +354,6 @@ export async function getStaticProps() { }; } else { marketTotals[swap.marketId] = { - // baseAsset: baseAsset, baseAssetIn: swap.baseAssetIn, baseAssetOut: swap.baseAssetOut, }; @@ -445,8 +364,6 @@ export async function getStaticProps() { return { ...traders, [accountId]: marketTotal }; }, {}); - console.log("tradersAggregatedByMarket", tradersAggregatedByMarket); - const tradeProfits = Object.keys( tradersAggregatedByMarket, ).reduce((ranks, accountId) => { @@ -455,7 +372,6 @@ export async function getStaticProps() { const marketsSummary: MarketSummary[] = []; const profit = Object.keys(trader).reduce((total, marketId) => { const marketTotal: MarketBaseDetails = trader[marketId]; - console.log("marketTotal", marketTotal); const market = markets.find((m) => m.marketId === Number(marketId)); @@ -463,10 +379,6 @@ export async function getStaticProps() { if (market?.status === "Resolved" && !suspiciousActivity) { const diff = marketTotal.baseAssetOut.minus(marketTotal.baseAssetIn); - // console.log("marketId:", marketId); - // console.log("diff", diff.div(ZTG).toString()); - // console.log(marketTotal.baseAssetOut.div(ZTG).toString()); - // console.log(marketTotal.baseAssetIn.div(ZTG).toString()); marketsSummary.push({ question: market.question!, @@ -483,9 +395,6 @@ export async function getStaticProps() { endTimestamp, ); - // console.log("usdprice", marketEndBaseAssetPrice?.toFixed(2)); - console.log(marketEndBaseAssetPrice); - const usdProfitLoss = diff.mul(marketEndBaseAssetPrice ?? 0); return total.plus(usdProfitLoss); } else { @@ -502,8 +411,6 @@ export async function getStaticProps() { }; }, {}); - console.log("tradeProfits", tradeProfits); - const rankings = Object.keys(tradeProfits) .reduce((rankings, accountId) => { rankings.push({ @@ -515,8 +422,7 @@ export async function getStaticProps() { }, []) .sort((a, b) => b.profitUsd - a.profitUsd); - const top20 = rankings; - // .slice(0, 20); + const top20 = rankings.slice(0, 20); const indentities = await Promise.all( top20.map((player) => sdk.api.query.identity.identityOf(player.accountId)), @@ -540,7 +446,6 @@ export async function getStaticProps() { const Leaderboard: NextPage<{ rankings: Rank[]; }> = ({ rankings }) => { - // console.log(rankings[0].markets); return (
From d9c7c94aa32a6904be23006f58b0b2e3fd51dbb5 Mon Sep 17 00:00:00 2001 From: Tom Robiquet Date: Fri, 7 Jul 2023 13:24:38 +0200 Subject: [PATCH 29/40] more cleanup --- pages/leaderboard.tsx | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/pages/leaderboard.tsx b/pages/leaderboard.tsx index 7e4be8425..84fcd4bc4 100644 --- a/pages/leaderboard.tsx +++ b/pages/leaderboard.tsx @@ -197,16 +197,7 @@ export async function getStaticProps() { const { markets } = await sdk.indexer.markets(); - const { historicalSwaps } = await sdk.indexer.historicalSwaps({ - where: { - // accountId_eq: "dE1CBAKzrE1C9R6NkgdEUNgv1H9x4xgT39wzSnxCtX3FpSqS8", //old ac - // accountId_eq: "dE3zfJtCC2YMHjgSifTbJg98EqhiVFeXvA8VCnCqyNty4ZYvv", //new ac creator - // accountId_eq: "dDyQQkwy5MmibHv5y1qQYpADS6x2x8yJjzaTRt2uTGfeSD7V9", //new ac lp - // accountId_eq: "dDywmamjrDkaT18ybCRJBfax65CoxJNSWGZfwiQrbkAe95wq3", - // accountId_eq: "dDyDMpv3YqFYdDmhqEdq8ZYnPU4gfXMSjqK6375CmTYF2Jt5W", - // accountId_eq: "dDyQQkwy5MmibHv5y1qQYpADS6x2x8yJjzaTRt2uTGfeSD7V9", - }, - }); + const { historicalSwaps } = await sdk.indexer.historicalSwaps(); const tradersWithSwaps = historicalSwaps.reduce((traders, swap) => { const trades = traders[swap.accountId]; @@ -295,7 +286,7 @@ export async function getStaticProps() { uniqueFullSetEvents.forEach((event) => { const trades = tradersWithSwaps[event.accountId]; - // probably this check is needed as accounts can aquire tokens via buy full sell or transfer + // this check is needed as accounts can aquire tokens via buy full sell or transfer if (trades) { const trade = convertEventToTrade(event); From bede00e6ead5f29b1434a9e572670f67ba1acc50 Mon Sep 17 00:00:00 2001 From: Tom Robiquet Date: Fri, 7 Jul 2023 13:33:59 +0200 Subject: [PATCH 30/40] fix merge --- components/portfolio/DepositButton.tsx | 2 -- lib/util/calc-scalar-winnings.spec.ts | 12 ------------ 2 files changed, 14 deletions(-) diff --git a/components/portfolio/DepositButton.tsx b/components/portfolio/DepositButton.tsx index e226e644b..f174cb4e7 100644 --- a/components/portfolio/DepositButton.tsx +++ b/components/portfolio/DepositButton.tsx @@ -132,8 +132,6 @@ const DepositModal = ({ if (!changedByUser) return; - //assumes source chain fee is paid in currency that is being transferred - const maxTransferAmount = balance.minus(fee?.mul(1.001) ?? 0); //add 0.1% buffer to fee if (name === "percentage") { setValue( "amount", diff --git a/lib/util/calc-scalar-winnings.spec.ts b/lib/util/calc-scalar-winnings.spec.ts index ee3f73e0b..85abea228 100644 --- a/lib/util/calc-scalar-winnings.spec.ts +++ b/lib/util/calc-scalar-winnings.spec.ts @@ -38,16 +38,4 @@ describe("calcScalarWinnings", () => { const { shortTokenValue } = calcScalarResolvedPrices(10, 40, 0); expect(shortTokenValue.toNumber()).toEqual(1); }); - - describe("getScalarIndexOf integration", () => { - // test("should return 1 for short", () => { - // const index = getScalarIndexOf({ - // ScalarOutcome: [1 as MarketId, "Short"], - // }); - - // expect(index).toEqual(1); - // }); - - test("should return 0 for long", () => {}); - }); }); From 48a717657e06f6c06f9572045ada48b1a991f856 Mon Sep 17 00:00:00 2001 From: Tom Robiquet Date: Fri, 7 Jul 2023 13:40:44 +0200 Subject: [PATCH 31/40] remove util usage --- pages/leaderboard.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pages/leaderboard.tsx b/pages/leaderboard.tsx index 84fcd4bc4..26db10d36 100644 --- a/pages/leaderboard.tsx +++ b/pages/leaderboard.tsx @@ -2,7 +2,6 @@ import { BaseAssetId, create, getMarketIdOf, - getScalarIndexOf, IOForeignAssetId, IOMarketOutcomeAssetId, IOScalarAssetId, @@ -97,7 +96,7 @@ const convertEventToTrade = ( if (marketId !== undefined) { if (event.event === "TokensRedeemed") { const assetValue = IOScalarAssetId.is(assetId) - ? getScalarIndexOf(assetId) === 1 + ? assetId.ScalarOutcome[1] === "Short" ? shortTokenVaue : longTokenVaue : new Decimal(1); From df1d60bdc78c0219f110836a16a033c9509399d2 Mon Sep 17 00:00:00 2001 From: Tom Robiquet Date: Mon, 10 Jul 2023 13:37:28 +0200 Subject: [PATCH 32/40] typo --- pages/leaderboard.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/leaderboard.tsx b/pages/leaderboard.tsx index 26db10d36..50b85b2ac 100644 --- a/pages/leaderboard.tsx +++ b/pages/leaderboard.tsx @@ -27,7 +27,7 @@ import { parseAssetIdString } from "lib/util/parse-asset-id"; import { FullHistoricalAccountBalanceFragment } from "@zeitgeistpm/indexer"; import { calcScalarResolvedPrices } from "lib/util/calc-scalar-winnings"; -// Approach: aggregate base asset movements in an out of a market +// Approach: aggregate base asset movements in and out of a market // "In events": swaps, buy full set // "Out events": swaps, sell full set, redeem From a0983153450c283dd0e5c9b442c877f923bc400e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rn=20Andre=20Tangen=20=40gorillatron?= Date: Tue, 11 Jul 2023 11:22:45 +0200 Subject: [PATCH 33/40] Update Oracle.tsx --- components/create/editor/inputs/Oracle.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/create/editor/inputs/Oracle.tsx b/components/create/editor/inputs/Oracle.tsx index 16de41e22..8996b6a41 100644 --- a/components/create/editor/inputs/Oracle.tsx +++ b/components/create/editor/inputs/Oracle.tsx @@ -68,7 +68,7 @@ export const OracleInput = forwardRef( }; const isSelectedAccount = wallet.realAddress === value; - const proxy = wallet.proxyFor[wallet.activeAccount.address]; + const proxy = wallet.proxyFor?.[wallet.activeAccount.address]; const accountname = proxy && proxy.enabled ? "Proxied" From d3b1135241bf6a4909f36509fd9b522c27242542 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rn=20Andre=20Tangen=20=40gorillatron?= Date: Tue, 11 Jul 2023 11:37:14 +0200 Subject: [PATCH 34/40] proxy fixes --- components/account/AccountSelect.tsx | 2 +- components/create/editor/inputs/Oracle.tsx | 2 +- components/portfolio/PortfolioIdentity.tsx | 2 +- pages/avatar/index.tsx | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/account/AccountSelect.tsx b/components/account/AccountSelect.tsx index 3c69b83a9..7f2e4c993 100644 --- a/components/account/AccountSelect.tsx +++ b/components/account/AccountSelect.tsx @@ -120,7 +120,7 @@ const AccountSelect: FC = ({ {wallet.activeAccount?.address && ( diff --git a/components/create/editor/inputs/Oracle.tsx b/components/create/editor/inputs/Oracle.tsx index 8996b6a41..49637a813 100644 --- a/components/create/editor/inputs/Oracle.tsx +++ b/components/create/editor/inputs/Oracle.tsx @@ -68,7 +68,7 @@ export const OracleInput = forwardRef( }; const isSelectedAccount = wallet.realAddress === value; - const proxy = wallet.proxyFor?.[wallet.activeAccount.address]; + const proxy = wallet.proxyFor?.[wallet.activeAccount?.address]; const accountname = proxy && proxy.enabled ? "Proxied" diff --git a/components/portfolio/PortfolioIdentity.tsx b/components/portfolio/PortfolioIdentity.tsx index 362c1ead5..e8fbd9402 100644 --- a/components/portfolio/PortfolioIdentity.tsx +++ b/components/portfolio/PortfolioIdentity.tsx @@ -10,7 +10,7 @@ const PortfolioIdentity = ({ address }: { address: string }) => { const wallet = useWallet(); const { data: identity } = useIdentity(address); - const proxy = wallet.proxyFor?.[wallet.activeAccount.address]; + const proxy = wallet.proxyFor?.[wallet.activeAccount?.address]; const isProxying = Boolean( proxy && proxy.enabled && proxy.address === address, diff --git a/pages/avatar/index.tsx b/pages/avatar/index.tsx index 20225a13c..890e46542 100644 --- a/pages/avatar/index.tsx +++ b/pages/avatar/index.tsx @@ -8,7 +8,7 @@ const Avatar = () => { const wallet = useWallet(); if (wallet.activeAccount) { - router.replace(`/avatar/${wallet.activeAccount.address}`); + router.replace(`/avatar/${wallet.activeAccount?.address}`); return <>; } From 43c0f9625d535be434694a68e908af891656a9f8 Mon Sep 17 00:00:00 2001 From: Tom Robiquet Date: Tue, 11 Jul 2023 11:50:29 +0200 Subject: [PATCH 35/40] Revalidate Static pages every 1 min --- pages/index.tsx | 2 +- pages/markets/[marketid].tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pages/index.tsx b/pages/index.tsx index 5f2eb97a6..3fe831a58 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -64,7 +64,7 @@ export async function getStaticProps() { categoryPlaceholders: categoryPlaceholders.map((c) => c.base64) ?? [], bannerPlaceHolders: bannerPlaceHolders.map((c) => c.base64) ?? [], }, - revalidate: 10 * 60, //10min + revalidate: 1 * 60, //1min }; } diff --git a/pages/markets/[marketid].tsx b/pages/markets/[marketid].tsx index 53c5a47f3..9bc6d0703 100644 --- a/pages/markets/[marketid].tsx +++ b/pages/markets/[marketid].tsx @@ -90,7 +90,7 @@ export async function getStaticProps({ params }) { resolutionTimestamp: resolutionTimestamp ?? null, promotionData, }, - revalidate: 10 * 60, //10mins + revalidate: 1 * 60, //1min }; } From df51d3c239ebbc8b5c54ed41d886b283120022df Mon Sep 17 00:00:00 2001 From: Tom Robiquet Date: Tue, 11 Jul 2023 12:03:22 +0200 Subject: [PATCH 36/40] remove market image --- pages/markets/[marketid].tsx | 9 --------- 1 file changed, 9 deletions(-) diff --git a/pages/markets/[marketid].tsx b/pages/markets/[marketid].tsx index 9bc6d0703..ef9ec8a90 100644 --- a/pages/markets/[marketid].tsx +++ b/pages/markets/[marketid].tsx @@ -9,7 +9,6 @@ import PoolDeployer from "components/markets/PoolDeployer"; import { MarketPromotionCallout } from "components/markets/PromotionCallout"; import ScalarPriceRange from "components/markets/ScalarPriceRange"; import MarketMeta from "components/meta/MarketMeta"; -import MarketImage from "components/ui/MarketImage"; import Skeleton from "components/ui/Skeleton"; import { ChartSeries } from "components/ui/TimeSeriesChart"; import Decimal from "decimal.js"; @@ -197,14 +196,6 @@ const Market: NextPage = ({ <>
- -
{promotionData && ( Date: Tue, 11 Jul 2023 12:05:53 +0200 Subject: [PATCH 37/40] don't fetch image --- lib/gql/markets.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/gql/markets.ts b/lib/gql/markets.ts index d8abe4c49..117e1f07b 100644 --- a/lib/gql/markets.ts +++ b/lib/gql/markets.ts @@ -32,7 +32,6 @@ const marketQuery = gql` question slug status - img outcomeAssets scalarType creator @@ -80,7 +79,6 @@ const marketQuery = gql` export interface MarketPageIndexedData { marketId: number; - img: string; slug: string; question: string; description: string; From f03fdfe1d9900ce43c5fa4d5220032bd40b4f434 Mon Sep 17 00:00:00 2001 From: Tom Robiquet Date: Tue, 11 Jul 2023 12:17:39 +0200 Subject: [PATCH 38/40] move key prop --- pages/leaderboard.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pages/leaderboard.tsx b/pages/leaderboard.tsx index 50b85b2ac..b88d6e178 100644 --- a/pages/leaderboard.tsx +++ b/pages/leaderboard.tsx @@ -443,8 +443,11 @@ const Leaderboard: NextPage<{
{rankings.map((rank, index) => ( -
-
+
+
{index + 1}
From bb7a80f42fdabfc1e48ef4f9469cd6ec234a473a Mon Sep 17 00:00:00 2001 From: Tom Robiquet Date: Tue, 11 Jul 2023 13:20:40 +0200 Subject: [PATCH 39/40] Simplify query. Decode text --- pages/leaderboard.tsx | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/pages/leaderboard.tsx b/pages/leaderboard.tsx index b88d6e178..8a5deb763 100644 --- a/pages/leaderboard.tsx +++ b/pages/leaderboard.tsx @@ -250,11 +250,7 @@ export async function getStaticProps() { { event_contains: "BoughtComplete", }, - { - AND: [ - { event_contains: "Deposited", assetId_not_contains: "pool" }, - ], - }, + { event_contains: "Deposited", assetId_not_contains: "pool" }, ], }, }); @@ -414,19 +410,25 @@ export async function getStaticProps() { const top20 = rankings.slice(0, 20); - const indentities = await Promise.all( + const identities = await Promise.all( top20.map((player) => sdk.api.query.identity.identityOf(player.accountId)), ); - const names: (string | undefined)[] = indentities.map( - (i) => (i.toHuman() as any)?.info?.display.Raw, + const textDecoder = new TextDecoder(); + + const names: (string | null)[] = identities.map((identity) => + identity.isNone === false + ? textDecoder.decode( + (identity.value.get("info") as any).get("display").value, + ) + : null, ); return { props: { rankings: top20.map((player, index) => ({ ...player, - name: names[index] ?? null, + name: names[index], })), revalidate: 10 * 60, //10min }, From 32cb4d84b2a67c840417278ae2c24e04859d1236 Mon Sep 17 00:00:00 2001 From: Tvrtko Majstorovic Date: Fri, 7 Jul 2023 18:09:48 +0200 Subject: [PATCH 40/40] fix asset filtering on exit pool - #1382 --- components/liquidity/ExitPoolForm.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/liquidity/ExitPoolForm.tsx b/components/liquidity/ExitPoolForm.tsx index 56ad94fb2..224f975d3 100644 --- a/components/liquidity/ExitPoolForm.tsx +++ b/components/liquidity/ExitPoolForm.tsx @@ -1,8 +1,8 @@ import { useQueryClient } from "@tanstack/react-query"; import { getIndexOf, + IOBaseAssetId, IOCategoricalAssetId, - IOZtgAssetId, isRpcSdk, parseAssetId, ZTG, @@ -63,7 +63,7 @@ const ExitPoolForm = ({ const assetId = weight && parseAssetId(weight.assetId).unwrap(); return ( - IOZtgAssetId.is(assetId) || + IOBaseAssetId.is(assetId) || (IOCategoricalAssetId.is(assetId) && market.resolvedOutcome === getIndexOf(assetId).toString()) );