From 359d1bf6ea65a7d13f72c4fef144d22b73205b7b Mon Sep 17 00:00:00 2001 From: Corey Soreff Date: Sat, 13 Sep 2025 09:44:35 +0900 Subject: [PATCH 1/8] Add staked balance to queried balance from db --- src/services/bakingBad/delegations/index.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/services/bakingBad/delegations/index.ts b/src/services/bakingBad/delegations/index.ts index e6a1965ba..0050dbe1c 100644 --- a/src/services/bakingBad/delegations/index.ts +++ b/src/services/bakingBad/delegations/index.ts @@ -44,6 +44,14 @@ export const getTokenVoteWeight = async (tokenAddress: string, account: string, EnvKey.REACT_APP_LITE_API_URL )}/network/${network}/token/${tokenAddress}/token-id/0/voting-power?userAddress=${account}&level=${level}` const response = await fetch(url) + + const stakedBalance = new BigNumber(0) + const stakedBalanceQuery = await fetch(`https://api.tzkt.io/v1/accounts/${account}`) + const stakedBalanceQueryResponse = await stakedBalanceQuery.json().stakedBalance + if (stakedBalanceQueryResponse.ok) { + stakedBalance.plus(stakedBalanceQueryResponse.stakedBalance) + } + if (!response.ok) { const data = await response.json() throw new Error(data.message) @@ -53,7 +61,7 @@ export const getTokenVoteWeight = async (tokenAddress: string, account: string, if (result) { return { votingWeight: new BigNumber(result.votingWeight), - votingXTZWeight: new BigNumber(result.votingXTZWeight) + votingXTZWeight: new BigNumber(result.votingXTZWeight + stakedBalance) } } From 5b10ad86722a6b4c8457d5c543999c586e3b8820 Mon Sep 17 00:00:00 2001 From: Corey Soreff Date: Sat, 13 Sep 2025 09:46:26 +0900 Subject: [PATCH 2/8] fix --- src/services/bakingBad/delegations/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/bakingBad/delegations/index.ts b/src/services/bakingBad/delegations/index.ts index 0050dbe1c..5db341179 100644 --- a/src/services/bakingBad/delegations/index.ts +++ b/src/services/bakingBad/delegations/index.ts @@ -47,7 +47,7 @@ export const getTokenVoteWeight = async (tokenAddress: string, account: string, const stakedBalance = new BigNumber(0) const stakedBalanceQuery = await fetch(`https://api.tzkt.io/v1/accounts/${account}`) - const stakedBalanceQueryResponse = await stakedBalanceQuery.json().stakedBalance + const stakedBalanceQueryResponse = await stakedBalanceQuery.json() if (stakedBalanceQueryResponse.ok) { stakedBalance.plus(stakedBalanceQueryResponse.stakedBalance) } From 4ff5cec5fcd1fb665f405d691442c71a2f6f1bf5 Mon Sep 17 00:00:00 2001 From: Corey Soreff Date: Sat, 13 Sep 2025 09:49:17 +0900 Subject: [PATCH 3/8] fix --- src/services/bakingBad/delegations/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/bakingBad/delegations/index.ts b/src/services/bakingBad/delegations/index.ts index 5db341179..467ebbd4e 100644 --- a/src/services/bakingBad/delegations/index.ts +++ b/src/services/bakingBad/delegations/index.ts @@ -47,8 +47,8 @@ export const getTokenVoteWeight = async (tokenAddress: string, account: string, const stakedBalance = new BigNumber(0) const stakedBalanceQuery = await fetch(`https://api.tzkt.io/v1/accounts/${account}`) - const stakedBalanceQueryResponse = await stakedBalanceQuery.json() - if (stakedBalanceQueryResponse.ok) { + if (stakedBalanceQuery.ok) { + const stakedBalanceQueryResponse = await stakedBalanceQuery.json() stakedBalance.plus(stakedBalanceQueryResponse.stakedBalance) } From 3980f6fa667bf1f8dc9588ccc732a454e26f2005 Mon Sep 17 00:00:00 2001 From: Corey Soreff Date: Sat, 13 Sep 2025 09:53:37 +0900 Subject: [PATCH 4/8] cleanup --- src/services/bakingBad/delegations/index.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/services/bakingBad/delegations/index.ts b/src/services/bakingBad/delegations/index.ts index 467ebbd4e..05fa24d00 100644 --- a/src/services/bakingBad/delegations/index.ts +++ b/src/services/bakingBad/delegations/index.ts @@ -45,11 +45,12 @@ export const getTokenVoteWeight = async (tokenAddress: string, account: string, )}/network/${network}/token/${tokenAddress}/token-id/0/voting-power?userAddress=${account}&level=${level}` const response = await fetch(url) - const stakedBalance = new BigNumber(0) - const stakedBalanceQuery = await fetch(`https://api.tzkt.io/v1/accounts/${account}`) + let stakedBalance = new BigNumber(0) + const stakedBalanceQuery = await fetch(`https://api.${networkNameMap[network]}.tzkt.io/v1/accounts/${account}`) + if (stakedBalanceQuery.ok) { const stakedBalanceQueryResponse = await stakedBalanceQuery.json() - stakedBalance.plus(stakedBalanceQueryResponse.stakedBalance) + stakedBalance = stakedBalance.plus(stakedBalanceQueryResponse.stakedBalance ?? 0) } if (!response.ok) { From 9871c7f251e285e4137df04b9334b646b5a0be37 Mon Sep 17 00:00:00 2001 From: Corey Soreff Date: Fri, 14 Nov 2025 20:42:37 +0900 Subject: [PATCH 5/8] Only add staked balance if not a delegate --- src/services/bakingBad/delegations/index.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/services/bakingBad/delegations/index.ts b/src/services/bakingBad/delegations/index.ts index 05fa24d00..4ad854551 100644 --- a/src/services/bakingBad/delegations/index.ts +++ b/src/services/bakingBad/delegations/index.ts @@ -46,11 +46,15 @@ export const getTokenVoteWeight = async (tokenAddress: string, account: string, const response = await fetch(url) let stakedBalance = new BigNumber(0) - const stakedBalanceQuery = await fetch(`https://api.${networkNameMap[network]}.tzkt.io/v1/accounts/${account}`) + const accountInfoResp = await fetch(`https://api.${networkNameMap[network]}.tzkt.io/v1/accounts/${account}`) - if (stakedBalanceQuery.ok) { - const stakedBalanceQueryResponse = await stakedBalanceQuery.json() - stakedBalance = stakedBalance.plus(stakedBalanceQueryResponse.stakedBalance ?? 0) + if (accountInfoResp.ok) { + const accountInfo = await accountInfoResp.json() + + // Only add staked balance if not a baker (delegate) + if (accountInfo.type !== "delegate") { + stakedBalance = stakedBalance.plus(accountInfo.stakedBalance ?? 0) + } } if (!response.ok) { @@ -59,10 +63,11 @@ export const getTokenVoteWeight = async (tokenAddress: string, account: string, } const result: { votingWeight: string; votingXTZWeight: string } = await response.json() + if (result) { return { votingWeight: new BigNumber(result.votingWeight), - votingXTZWeight: new BigNumber(result.votingXTZWeight + stakedBalance) + votingXTZWeight: new BigNumber(result.votingXTZWeight).plus(stakedBalance) } } From 1099dbaa130a75ac21e4cf54184356c2edbfd1f0 Mon Sep 17 00:00:00 2001 From: Corey Soreff Date: Fri, 14 Nov 2025 23:15:59 +0900 Subject: [PATCH 6/8] Cleanup --- src/services/bakingBad/delegations/index.ts | 112 ++++++++++---------- 1 file changed, 55 insertions(+), 57 deletions(-) diff --git a/src/services/bakingBad/delegations/index.ts b/src/services/bakingBad/delegations/index.ts index 4ad854551..9e0bee61f 100644 --- a/src/services/bakingBad/delegations/index.ts +++ b/src/services/bakingBad/delegations/index.ts @@ -1,78 +1,76 @@ +import BigNumber from "bignumber.js" import { Network } from "services/beacon" +import { EnvKey, getEnv } from "services/config" import { networkNameMap } from ".." import { DelegationDTO, TokenDelegationDTO } from "./types" -import BigNumber from "bignumber.js" -import { EnvKey, getEnv } from "services/config" - -export const getLatestDelegation = async (daoAddress: string, network: Network) => { - const url = `https://api.${networkNameMap[network]}.tzkt.io/v1/operations/delegations?sender=${daoAddress}&status=applied` - const response = await fetch(url) - if (!response.ok) { - throw new Error("Failed to fetch delegations from TZKT API") - } - const resultingDelegations: DelegationDTO[] = await response.json() +const BN = (v: BigNumber.Value) => new BigNumber(v ?? 0) - if (!resultingDelegations.length) { - return null +async function fetchJson(input: RequestInfo | URL, init?: RequestInit): Promise { + const res = await fetch(input, init) + if (!res.ok) { + let body: any + try { + body = await res.json() + } catch { + body = await res.text() + } + const msg = (body && (body.message || body.error)) || res.statusText + throw new Error(`HTTP ${res.status}: ${msg}`) } - - return resultingDelegations[0] + return (await res.json()) as T } -export const getTokenDelegation = async (tokenAddress: string, account: string, network: Network) => { - const url = `https://api.${networkNameMap[network]}.tzkt.io/v1/contracts/${tokenAddress}/bigmaps/delegates/keys?key.eq=${account}&active=true` - const response = await fetch(url) - - if (!response.ok) { - throw new Error("Failed to fetch token delegations from TZKT API") - } - - const resultingDelegations: TokenDelegationDTO[] = await response.json() - - if (resultingDelegations.length === 0) { - return null - } +function tzktBase(network: Network) { + return `https://api.${networkNameMap[network]}.tzkt.io/v1` +} - const delegatedTo = resultingDelegations[0].value +export const getLatestDelegation = async (daoAddress: string, network: Network) => { + // smallest payload: only one most recent, sorted by id desc + const url = `${tzktBase(network)}/operations/delegations?sender=${daoAddress}&status=applied&limit=1&sort.desc=id` + const delegations = await fetchJson(url) - return delegatedTo + if (!delegations.length) return null + return delegations[0] } -export const getTokenVoteWeight = async (tokenAddress: string, account: string, network: Network, level: string) => { - const url = `${getEnv( - EnvKey.REACT_APP_LITE_API_URL - )}/network/${network}/token/${tokenAddress}/token-id/0/voting-power?userAddress=${account}&level=${level}` - const response = await fetch(url) - - let stakedBalance = new BigNumber(0) - const accountInfoResp = await fetch(`https://api.${networkNameMap[network]}.tzkt.io/v1/accounts/${account}`) +export const getTokenDelegation = async (tokenAddress: string, account: string, network: Network) => { + // ask bigmap for a single active key for this account; return just the 'value' + const url = + `${tzktBase(network)}/contracts/${tokenAddress}/bigmaps/delegates/keys` + + `?key.eq=${account}&active=true&limit=1&select=value` + + // TzKT returns an array; with select=value it’s an array of the value type + const arr = await fetchJson>(url) + if (arr.length === 0) return null + return arr[0] +} - if (accountInfoResp.ok) { - const accountInfo = await accountInfoResp.json() +type VotingPowerResponse = { votingWeight: string; votingXTZWeight: string } +type VoteWeight = { votingWeight: BigNumber; votingXTZWeight: BigNumber } - // Only add staked balance if not a baker (delegate) - if (accountInfo.type !== "delegate") { - stakedBalance = stakedBalance.plus(accountInfo.stakedBalance ?? 0) - } - } +export const getTokenVoteWeight = async ( + tokenAddress: string, + account: string, + network: Network, + level: string +): Promise => { + const votingPowerUrl = + `${getEnv(EnvKey.REACT_APP_LITE_API_URL)}/network/${network}/token/${tokenAddress}` + + `/token-id/0/voting-power?userAddress=${account}&level=${level}` - if (!response.ok) { - const data = await response.json() - throw new Error(data.message) - } + const voting = await fetchJson(votingPowerUrl) - const result: { votingWeight: string; votingXTZWeight: string } = await response.json() + // 2) Tez full_balance including staked/etc at the given level + const fullBalanceUrl = + `https://tcinfra.net/rpc/tezos/${networkNameMap[network]}` + + `/chains/main/blocks/${level}/context/contracts/${account}/full_balance` - if (result) { - return { - votingWeight: new BigNumber(result.votingWeight), - votingXTZWeight: new BigNumber(result.votingXTZWeight).plus(stakedBalance) - } - } + const balanceStr = await fetchJson(fullBalanceUrl) + const fullTezBalance = BN(balanceStr) return { - votingWeight: new BigNumber(0), - votingXTZWeight: new BigNumber(0) + votingWeight: BN(voting.votingWeight), + votingXTZWeight: fullTezBalance } } From 3ca5f163d02e595696c624f86e3a32f17e6e82d8 Mon Sep 17 00:00:00 2001 From: Corey Soreff Date: Fri, 14 Nov 2025 23:27:12 +0900 Subject: [PATCH 7/8] revert --- src/services/bakingBad/delegations/index.ts | 113 ++++++++++---------- 1 file changed, 58 insertions(+), 55 deletions(-) diff --git a/src/services/bakingBad/delegations/index.ts b/src/services/bakingBad/delegations/index.ts index 9e0bee61f..a0e21ce6c 100644 --- a/src/services/bakingBad/delegations/index.ts +++ b/src/services/bakingBad/delegations/index.ts @@ -1,76 +1,79 @@ -import BigNumber from "bignumber.js" import { Network } from "services/beacon" -import { EnvKey, getEnv } from "services/config" import { networkNameMap } from ".." import { DelegationDTO, TokenDelegationDTO } from "./types" +import BigNumber from "bignumber.js" +import { EnvKey, getEnv } from "services/config" -const BN = (v: BigNumber.Value) => new BigNumber(v ?? 0) - -async function fetchJson(input: RequestInfo | URL, init?: RequestInit): Promise { - const res = await fetch(input, init) - if (!res.ok) { - let body: any - try { - body = await res.json() - } catch { - body = await res.text() - } - const msg = (body && (body.message || body.error)) || res.statusText - throw new Error(`HTTP ${res.status}: ${msg}`) +export const getLatestDelegation = async (daoAddress: string, network: Network) => { + const url = `https://api.${networkNameMap[network]}.tzkt.io/v1/operations/delegations?sender=${daoAddress}&status=applied` + const response = await fetch(url) + if (!response.ok) { + throw new Error("Failed to fetch delegations from TZKT API") } - return (await res.json()) as T -} -function tzktBase(network: Network) { - return `https://api.${networkNameMap[network]}.tzkt.io/v1` -} + const resultingDelegations: DelegationDTO[] = await response.json() -export const getLatestDelegation = async (daoAddress: string, network: Network) => { - // smallest payload: only one most recent, sorted by id desc - const url = `${tzktBase(network)}/operations/delegations?sender=${daoAddress}&status=applied&limit=1&sort.desc=id` - const delegations = await fetchJson(url) + if (!resultingDelegations.length) { + return null + } - if (!delegations.length) return null - return delegations[0] + return resultingDelegations[0] } export const getTokenDelegation = async (tokenAddress: string, account: string, network: Network) => { - // ask bigmap for a single active key for this account; return just the 'value' - const url = - `${tzktBase(network)}/contracts/${tokenAddress}/bigmaps/delegates/keys` + - `?key.eq=${account}&active=true&limit=1&select=value` - - // TzKT returns an array; with select=value it’s an array of the value type - const arr = await fetchJson>(url) - if (arr.length === 0) return null - return arr[0] + const url = `https://api.${networkNameMap[network]}.tzkt.io/v1/contracts/${tokenAddress}/bigmaps/delegates/keys?key.eq=${account}&active=true` + const response = await fetch(url) + + if (!response.ok) { + throw new Error("Failed to fetch token delegations from TZKT API") + } + + const resultingDelegations: TokenDelegationDTO[] = await response.json() + + if (resultingDelegations.length === 0) { + return null + } + + const delegatedTo = resultingDelegations[0].value + + return delegatedTo } -type VotingPowerResponse = { votingWeight: string; votingXTZWeight: string } -type VoteWeight = { votingWeight: BigNumber; votingXTZWeight: BigNumber } +export const getTokenVoteWeight = async (tokenAddress: string, account: string, network: Network, level: string) => { + const url = `${getEnv( + EnvKey.REACT_APP_LITE_API_URL + )}/network/${network}/token/${tokenAddress}/token-id/0/voting-power?userAddress=${account}&level=${level}` + const response = await fetch(url) -export const getTokenVoteWeight = async ( - tokenAddress: string, - account: string, - network: Network, - level: string -): Promise => { - const votingPowerUrl = - `${getEnv(EnvKey.REACT_APP_LITE_API_URL)}/network/${network}/token/${tokenAddress}` + - `/token-id/0/voting-power?userAddress=${account}&level=${level}` + let fullTezBalance = new BigNumber(0) + const fullTezBalanceResp = await fetch( + `https://tcinfra.net/rpc/tezos/${networkNameMap[network]}/chains/main/blocks/${level}/context/contracts/${account}/full_balance` + ) - const voting = await fetchJson(votingPowerUrl) + if (fullTezBalanceResp.ok) { + const balanceStr = await fullTezBalanceResp.json() // e.g., "123456789" + fullTezBalance = fullTezBalance.plus(new BigNumber(balanceStr ?? 0)) + } else { + const fullTezBalanceRespData = await fullTezBalanceResp.json() + throw new Error(fullTezBalanceRespData.message) + } + + if (!response.ok) { + const data = await response.json() + throw new Error(data.message) + } - // 2) Tez full_balance including staked/etc at the given level - const fullBalanceUrl = - `https://tcinfra.net/rpc/tezos/${networkNameMap[network]}` + - `/chains/main/blocks/${level}/context/contracts/${account}/full_balance` + const result: { votingWeight: string; votingXTZWeight: string } = await response.json() - const balanceStr = await fetchJson(fullBalanceUrl) - const fullTezBalance = BN(balanceStr) + if (result) { + return { + votingWeight: new BigNumber(result.votingWeight), + votingXTZWeight: fullTezBalance + } + } return { - votingWeight: BN(voting.votingWeight), - votingXTZWeight: fullTezBalance + votingWeight: new BigNumber(0), + votingXTZWeight: new BigNumber(0) } } From 83142d75c6c514712a2e5a64a2e6502808953e82 Mon Sep 17 00:00:00 2001 From: Corey Soreff Date: Fri, 14 Nov 2025 23:50:24 +0900 Subject: [PATCH 8/8] test --- src/services/bakingBad/delegations/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/services/bakingBad/delegations/index.ts b/src/services/bakingBad/delegations/index.ts index a0e21ce6c..8c06a60ff 100644 --- a/src/services/bakingBad/delegations/index.ts +++ b/src/services/bakingBad/delegations/index.ts @@ -53,6 +53,7 @@ export const getTokenVoteWeight = async (tokenAddress: string, account: string, if (fullTezBalanceResp.ok) { const balanceStr = await fullTezBalanceResp.json() // e.g., "123456789" fullTezBalance = fullTezBalance.plus(new BigNumber(balanceStr ?? 0)) + console.log(fullTezBalance) } else { const fullTezBalanceRespData = await fullTezBalanceResp.json() throw new Error(fullTezBalanceRespData.message)