min stake from backend (#78)
resolves #74 Co-authored-by: johba <johba@harb.eth> Reviewed-on: https://codeberg.org/johba/harb/pulls/78
This commit is contained in:
parent
0b3545091f
commit
bd475c2271
11 changed files with 1176 additions and 1977 deletions
|
|
@ -30,6 +30,7 @@ type stats {
|
|||
stakeTotalSupply: BigInt!
|
||||
outstandingStake: BigInt!
|
||||
positionsUpdatedAt: BigInt!
|
||||
minStake: BigInt!
|
||||
totalMinted: BigInt!
|
||||
totalBurned: BigInt!
|
||||
totalTaxPaid: BigInt!
|
||||
|
|
@ -102,6 +103,14 @@ input statsFilter {
|
|||
positionsUpdatedAt_lt: BigInt
|
||||
positionsUpdatedAt_gte: BigInt
|
||||
positionsUpdatedAt_lte: BigInt
|
||||
minStake: BigInt
|
||||
minStake_not: BigInt
|
||||
minStake_in: [BigInt]
|
||||
minStake_not_in: [BigInt]
|
||||
minStake_gt: BigInt
|
||||
minStake_lt: BigInt
|
||||
minStake_gte: BigInt
|
||||
minStake_lte: BigInt
|
||||
totalMinted: BigInt
|
||||
totalMinted_not: BigInt
|
||||
totalMinted_in: [BigInt]
|
||||
|
|
@ -419,4 +428,4 @@ input positionsFilter {
|
|||
payout_lt: BigInt
|
||||
payout_gte: BigInt
|
||||
payout_lte: BigInt
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,10 @@ export const stats = onchainTable('stats', t => ({
|
|||
.bigint()
|
||||
.notNull()
|
||||
.$default(() => 0n),
|
||||
minStake: t
|
||||
.bigint()
|
||||
.notNull()
|
||||
.$default(() => 0n),
|
||||
|
||||
// Totals
|
||||
totalMinted: t
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ export async function ensureStatsExists(context: StatsContext, timestamp?: bigin
|
|||
}
|
||||
};
|
||||
|
||||
const [kraikenTotalSupply, stakeTotalSupply, outstandingStake] = await Promise.all([
|
||||
const [kraikenTotalSupply, stakeTotalSupply, outstandingStake, minStake] = await Promise.all([
|
||||
readWithFallback(
|
||||
() =>
|
||||
client.readContract({
|
||||
|
|
@ -163,6 +163,16 @@ export async function ensureStatsExists(context: StatsContext, timestamp?: bigin
|
|||
0n,
|
||||
'Stake.outstandingStake'
|
||||
),
|
||||
readWithFallback(
|
||||
() =>
|
||||
client.readContract({
|
||||
abi: contracts.Kraiken.abi,
|
||||
address: contracts.Kraiken.address,
|
||||
functionName: 'minStake',
|
||||
}),
|
||||
0n,
|
||||
'Kraiken.minStake'
|
||||
),
|
||||
]);
|
||||
|
||||
cachedStakeTotalSupply = stakeTotalSupply;
|
||||
|
|
@ -178,6 +188,7 @@ export async function ensureStatsExists(context: StatsContext, timestamp?: bigin
|
|||
ringBufferPointer: 0,
|
||||
lastHourlyUpdateTimestamp: currentHour,
|
||||
ringBuffer: serializeRingBuffer(makeEmptyRingBuffer()),
|
||||
minStake,
|
||||
});
|
||||
|
||||
statsData = await context.db.find(stats, { id: STATS_ID });
|
||||
|
|
@ -295,3 +306,33 @@ export async function refreshOutstandingStake(context: StatsContext) {
|
|||
outstandingStake,
|
||||
});
|
||||
}
|
||||
|
||||
export async function refreshMinStake(context: StatsContext, statsData?: Awaited<ReturnType<typeof ensureStatsExists>>) {
|
||||
let currentStats = statsData;
|
||||
if (!currentStats) {
|
||||
currentStats = await context.db.find(stats, { id: STATS_ID });
|
||||
}
|
||||
if (!currentStats) {
|
||||
currentStats = await ensureStatsExists(context);
|
||||
}
|
||||
if (!currentStats) return;
|
||||
|
||||
let minStake: bigint;
|
||||
try {
|
||||
minStake = await context.client.readContract({
|
||||
abi: context.contracts.Kraiken.abi,
|
||||
address: context.contracts.Kraiken.address,
|
||||
functionName: 'minStake',
|
||||
});
|
||||
} catch (error) {
|
||||
const logger = context.logger || console;
|
||||
logger.warn('[stats.refreshMinStake] Failed to read Kraiken.minStake', error);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((currentStats.minStake ?? 0n) === minStake) return;
|
||||
|
||||
await context.db.update(stats, { id: STATS_ID }).set({
|
||||
minStake,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,11 +4,13 @@ import type { Context } from 'ponder:registry';
|
|||
/**
|
||||
* Validates that the deployed Kraiken contract version is compatible
|
||||
* with this indexer's kraiken-lib version.
|
||||
*
|
||||
*
|
||||
* MUST be called at Ponder startup before processing any events.
|
||||
* Fails hard (process.exit) on mismatch to prevent indexing wrong data.
|
||||
*/
|
||||
export async function validateContractVersion(context: Context): Promise<void> {
|
||||
const logger = context.logger || console;
|
||||
|
||||
try {
|
||||
const contractVersion = await context.client.readContract({
|
||||
address: context.contracts.Kraiken.address,
|
||||
|
|
@ -19,14 +21,14 @@ export async function validateContractVersion(context: Context): Promise<void> {
|
|||
const versionNumber = Number(contractVersion);
|
||||
|
||||
if (!isCompatibleVersion(versionNumber)) {
|
||||
console.error(getVersionMismatchError(versionNumber, 'ponder'));
|
||||
logger.error(getVersionMismatchError(versionNumber, 'ponder'));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`✓ Contract version validated: v${versionNumber} (kraiken-lib v${KRAIKEN_LIB_VERSION})`);
|
||||
logger.info(`✓ Contract version validated: v${versionNumber} (kraiken-lib v${KRAIKEN_LIB_VERSION})`);
|
||||
} catch (error) {
|
||||
console.error('Failed to read contract VERSION:', error);
|
||||
console.error('Ensure Kraiken contract has VERSION constant and is deployed correctly');
|
||||
logger.error('Failed to read contract VERSION:', error);
|
||||
logger.error('Ensure Kraiken contract has VERSION constant and is deployed correctly');
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import {
|
|||
updateHourlyData,
|
||||
checkBlockHistorySufficient,
|
||||
RING_BUFFER_SEGMENTS,
|
||||
refreshMinStake,
|
||||
} from './helpers/stats';
|
||||
import { validateContractVersion } from './helpers/version';
|
||||
|
||||
|
|
@ -80,7 +81,9 @@ ponder.on('Kraiken:Transfer', async ({ event, context }) => {
|
|||
});
|
||||
|
||||
ponder.on('StatsBlock:block', async ({ event, context }) => {
|
||||
await ensureStatsExists(context, event.block.timestamp);
|
||||
const statsData = await ensureStatsExists(context, event.block.timestamp);
|
||||
|
||||
await refreshMinStake(context, statsData);
|
||||
|
||||
// Only update hourly data if we have sufficient block history
|
||||
if (checkBlockHistorySufficient(context, event)) {
|
||||
|
|
|
|||
3017
web-app/package-lock.json
generated
3017
web-app/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -155,7 +155,6 @@ import { useClaim } from '@/composables/useClaim';
|
|||
import { useAdjustTaxRate } from '@/composables/useAdjustTaxRates';
|
||||
import { useSnatchSelection } from '@/composables/useSnatchSelection';
|
||||
import { assetsToShares } from '@/contracts/stake';
|
||||
import { getMinStake } from '@/contracts/harb';
|
||||
import { useWallet } from '@/composables/useWallet';
|
||||
import { ref, onMounted, watch, computed, watchEffect, getCurrentInstance } from 'vue';
|
||||
import { useStatCollection, loadStats } from '@/composables/useStatCollection';
|
||||
|
|
@ -187,7 +186,7 @@ const snatchLabelId = `stake-snatch-${uid}`;
|
|||
const stakeSummaryId = `stake-summary-${uid}`;
|
||||
const formStatusId = `stake-status-${uid}`;
|
||||
|
||||
const minStake = ref<bigint>(0n);
|
||||
const minStake = computed(() => statCollection.minStake ?? 0n);
|
||||
const stakeSlots = ref<string>('0.00');
|
||||
const supplyFreeze = ref<number>(0);
|
||||
let debounceTimer: ReturnType<typeof setTimeout>;
|
||||
|
|
@ -203,7 +202,6 @@ watchEffect(() => {
|
|||
stake.stakingAmountShares = await assetsToShares(stake.stakingAmount);
|
||||
const stakingAmountSharesNumber = bigInt2Number(stake.stakingAmountShares, 18);
|
||||
const stakeableSupplyNumber = bigInt2Number(statCollection.stakeableSupply, 18);
|
||||
minStake.value = await getMinStake();
|
||||
|
||||
if (stakeableSupplyNumber === 0) {
|
||||
supplyFreeze.value = 0;
|
||||
|
|
@ -502,7 +500,6 @@ async function handleSubmit() {
|
|||
}
|
||||
|
||||
onMounted(async () => {
|
||||
minStake.value = await getMinStake();
|
||||
stake.stakingAmountNumber = minStakeAmount.value;
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -17,20 +17,15 @@ const { darkTheme } = useDark();
|
|||
const wallet = useWallet();
|
||||
const initialChainId = wallet.account.chainId ?? DEFAULT_CHAIN_ID;
|
||||
const { activePositions } = usePositions(initialChainId);
|
||||
const ignoreOwner = ref(false);
|
||||
|
||||
const taxRate = ref<number>(1.0);
|
||||
|
||||
const stake = useStake();
|
||||
const statCollection = useStatCollection(initialChainId);
|
||||
const minStake = computed(() => statCollection.minStake ?? 0n);
|
||||
const minStakeAmount = computed(() => {
|
||||
return formatBigIntDivision(minStake.value, 10n ** 18n);
|
||||
});
|
||||
const ignoreOwner = ref(false);
|
||||
|
||||
const stakeAbleHarbAmount = computed(() => statCollection.kraikenTotalSupply / 5n);
|
||||
|
||||
const minStake = computed(() => stakeAbleHarbAmount.value / 600n);
|
||||
|
||||
const stake = useStake();
|
||||
const statCollection = useStatCollection(initialChainId);
|
||||
const taxRate = ref<number>(1.0);
|
||||
const snatchPositions = computed(() => {
|
||||
if (
|
||||
bigInt2Number(statCollection.outstandingStake, 18) + stake.stakingAmountNumber <=
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { config } from '@/wagmi';
|
|||
import logger from '@/utils/logger';
|
||||
import type { WatchBlocksReturnType } from 'viem';
|
||||
import { bigInt2Number } from '@/utils/helper';
|
||||
import { minStake as stakeMinStake } from '@/contracts/stake';
|
||||
import { DEFAULT_CHAIN_ID } from '@/config';
|
||||
import { createRetryManager, formatGraphqlError, resolveGraphqlEndpoint } from '@/utils/graphqlRetry';
|
||||
const demo = sessionStorage.getItem('demo') === 'true';
|
||||
|
|
@ -17,6 +18,7 @@ interface StatsRecord {
|
|||
burnedLastDay: string;
|
||||
burnedLastWeek: string;
|
||||
id: string;
|
||||
minStake: string;
|
||||
mintNextHourProjected: string;
|
||||
mintedLastDay: string;
|
||||
mintedLastWeek: string;
|
||||
|
|
@ -44,6 +46,7 @@ export async function loadStatsCollection(chainId: number, endpointOverride?: st
|
|||
{
|
||||
query: `query StatsQuery {
|
||||
stats(id: "0x01") {
|
||||
minStake
|
||||
burnNextHourProjected
|
||||
burnedLastDay
|
||||
burnedLastWeek
|
||||
|
|
@ -134,6 +137,14 @@ const stakeTotalSupply = computed(() => {
|
|||
}
|
||||
});
|
||||
|
||||
const minStake = computed(() => {
|
||||
if (rawStatsCollections.value?.length > 0) {
|
||||
return BigInt(rawStatsCollections.value[0].minStake);
|
||||
} else {
|
||||
return 0n;
|
||||
}
|
||||
});
|
||||
|
||||
//Total Supply Change / 7d=mintedLastWeek−burnedLastWeek
|
||||
const totalSupplyChange7d = computed(() => {
|
||||
if (rawStatsCollections.value?.length > 0) {
|
||||
|
|
@ -207,9 +218,11 @@ export async function loadStats(chainId?: number) {
|
|||
statsError.value = null;
|
||||
retryManager.reset();
|
||||
retryManager.clear();
|
||||
stakeMinStake.value = minStake.value;
|
||||
} catch (error) {
|
||||
rawStatsCollections.value = [];
|
||||
statsError.value = formatGraphqlError(error);
|
||||
stakeMinStake.value = 0n;
|
||||
retryManager.schedule();
|
||||
} finally {
|
||||
loading.value = false;
|
||||
|
|
@ -269,5 +282,6 @@ export function useStatCollection(chainId: number = DEFAULT_CHAIN_ID) {
|
|||
claimedSlots,
|
||||
statsError,
|
||||
loading,
|
||||
minStake,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,31 +61,6 @@ export async function getAllowance() {
|
|||
return result;
|
||||
}
|
||||
|
||||
export async function getMinStake() {
|
||||
logger.contract('getMinStake');
|
||||
|
||||
const publicClient = getWalletPublicClient();
|
||||
if (publicClient) {
|
||||
const result = (await publicClient.readContract({
|
||||
abi: HarbContract.abi,
|
||||
address: HarbContract.contractAddress,
|
||||
functionName: 'minStake',
|
||||
args: [],
|
||||
})) as bigint;
|
||||
allowance.value = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
const result: bigint = (await readContract(config as Config, {
|
||||
abi: HarbContract.abi,
|
||||
address: HarbContract.contractAddress,
|
||||
functionName: 'minStake',
|
||||
args: [],
|
||||
})) as bigint;
|
||||
allowance.value = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function getNonce() {
|
||||
logger.contract('getNonce');
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ interface Contract {
|
|||
contractAddress: Address;
|
||||
}
|
||||
|
||||
export const minStake = ref();
|
||||
export const minStake = ref<bigint>(0n);
|
||||
export const totalSupply = ref(0n);
|
||||
export const outstandingSupply = ref(0n);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue