Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions atp-indexer/ponder.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,21 @@ export const stakedWithProvider = onchainTable("staked_with_provider", (t) => ({
stakedAmount: t.bigint().notNull(),
providerTakeRate: t.integer().notNull(),
providerRewardsRecipient: t.hex().notNull(),
/**
* Whether this stake was deposited with `_moveWithLatestRollup = true`.
* Decoded from the originating tx's calldata at insert time. Nullable
* for rows where decoding failed (unknown entry point, calldata mangled,
* etc.) — callers should treat null as "consult the on-chain probe".
*/
moveWithRollup: t.boolean(),
/**
* The rollup that currently holds the live record for this stake.
* Starts equal to `rollupAddress`. Updated to the new canonical rollup
* by the `Registry:CanonicalRollupUpdated` handler whenever
* `moveWithRollup = true`. The dashboard reads this as a fast hint and
* still falls back to the on-chain probe for safety.
*/
effectiveRollup: t.hex().notNull(),
txHash: t.hex().notNull(),
blockNumber: t.bigint().notNull(),
logIndex: t.integer().notNull(),
Expand All @@ -82,6 +97,7 @@ export const stakedWithProvider = onchainTable("staked_with_provider", (t) => ({
atpAddressIdx: index().on(table.atpAddress),
providerIdentifierIdx: index().on(table.providerIdentifier),
attesterAddressIdx: index().on(table.attesterAddress),
effectiveRollupIdx: index().on(table.effectiveRollup),
}));

export const stakedWithProviderRelations = relations(stakedWithProvider, ({ one }) => ({
Expand Down Expand Up @@ -109,6 +125,10 @@ export const erc20StakedWithProvider = onchainTable("erc20_staked_with_provider"
stakedAmount: t.bigint().notNull(),
providerTakeRate: t.integer().notNull(),
providerRewardsRecipient: t.hex().notNull(),
/** See `stakedWithProvider.moveWithRollup`. */
moveWithRollup: t.boolean(),
/** See `stakedWithProvider.effectiveRollup`. */
effectiveRollup: t.hex().notNull(),
txHash: t.hex().notNull(),
blockNumber: t.bigint().notNull(),
logIndex: t.integer().notNull(),
Expand All @@ -117,6 +137,7 @@ export const erc20StakedWithProvider = onchainTable("erc20_staked_with_provider"
stakerAddressIdx: index().on(table.stakerAddress),
providerIdentifierIdx: index().on(table.providerIdentifier),
attesterAddressIdx: index().on(table.attesterAddress),
effectiveRollupIdx: index().on(table.effectiveRollup),
}));

export const erc20StakedWithProviderRelations = relations(erc20StakedWithProvider, ({ one }) => ({
Expand All @@ -137,13 +158,18 @@ export const staked = onchainTable("staked", (t) => ({
attesterAddress: t.hex().notNull(),
rollupAddress: t.hex().notNull(),
stakedAmount: t.bigint().notNull(),
/** See `stakedWithProvider.moveWithRollup`. */
moveWithRollup: t.boolean(),
/** See `stakedWithProvider.effectiveRollup`. */
effectiveRollup: t.hex().notNull(),
txHash: t.hex().notNull(),
blockNumber: t.bigint().notNull(),
logIndex: t.integer().notNull(),
timestamp: t.bigint().notNull(),
}), (table) => ({
atpAddressIdx: index().on(table.atpAddress),
attesterAddressIdx: index().on(table.attesterAddress),
effectiveRollupIdx: index().on(table.effectiveRollup),
}));

export const stakedRelations = relations(staked, ({ one }) => ({
Expand Down Expand Up @@ -321,12 +347,17 @@ export const deposit = onchainTable("deposit", (t) => ({
proofOfPossessionX: t.bigint().notNull(),
proofOfPossessionY: t.bigint().notNull(),
amount: t.bigint().notNull(),
/** See `stakedWithProvider.moveWithRollup`. */
moveWithRollup: t.boolean(),
/** See `stakedWithProvider.effectiveRollup`. */
effectiveRollup: t.hex().notNull(),
txHash: t.hex().notNull(),
blockNumber: t.bigint().notNull(),
logIndex: t.integer().notNull(),
timestamp: t.bigint().notNull(),
}), (table) => ({
attesterAddressIdx: index().on(table.attesterAddress),
effectiveRollupIdx: index().on(table.effectiveRollup),
}));

/**
Expand Down
12 changes: 12 additions & 0 deletions atp-indexer/src/api/handlers/atp/details.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ function formatDirectStakes(
attesterAddress: checksumAddress(stake.attesterAddress),
operatorAddress: checksumAddress(stake.operatorAddress),
rollupAddress: checksumAddress(stake.rollupAddress),
// Fast-path hint for unstake routing (see `staked.effectiveRollup`).
// Falls back to `rollupAddress` for rows backfilled before the
// column existed.
moveWithRollup: stake.moveWithRollup ?? null,
effectiveRollup: stake.effectiveRollup
? checksumAddress(stake.effectiveRollup)
: checksumAddress(stake.rollupAddress),
stakedAmount: activationThreshold,
totalSlashed: totalSlashed.toString(),
txHash: stake.txHash,
Expand Down Expand Up @@ -65,6 +72,11 @@ function formatDelegations(
providerLogo: metadata?.providerLogoUrl || '',
operatorAddress: checksumAddress(op.attesterAddress),
rollupAddress: checksumAddress(op.rollupAddress),
// See formatDirectStakes for the rationale.
moveWithRollup: op.moveWithRollup ?? null,
effectiveRollup: op.effectiveRollup
? checksumAddress(op.effectiveRollup)
: checksumAddress(op.rollupAddress),
stakedAmount: activationThreshold,
totalSlashed: totalSlashed.toString(),
splitContract: checksumAddress(op.splitContractAddress),
Expand Down
21 changes: 21 additions & 0 deletions atp-indexer/src/api/handlers/staking/beneficiary-overview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,13 @@ export async function handleBeneficiaryStakingOverview(c: Context): Promise<Resp
atpAddress: checksumAddress(atpByStaker.get(stake.stakerAddress.toLowerCase()) || stake.atpAddress),
attesterAddress: checksumAddress(stake.attesterAddress),
rollupAddress: checksumAddress(stake.rollupAddress),
// Hints for the dashboard's fast-path unstake routing. See
// `staked.moveWithRollup` / `staked.effectiveRollup` on the schema.
// `moveWithRollup` may be null when the originating tx's entry
// point isn't one we recognise (e.g., a future Staker variant) —
// the dashboard's on-chain probe is the safety net for those rows.
moveWithRollup: stake.moveWithRollup,
effectiveRollup: checksumAddress(stake.effectiveRollup),
stakedAmount: stake.stakedAmount.toString(),
hasFailedDeposit: stake.hasFailedDeposit,
failedDepositTxHash: stake.failedDepositTxHash,
Expand All @@ -152,6 +159,9 @@ export async function handleBeneficiaryStakingOverview(c: Context): Promise<Resp
providerLogo: metadata?.providerLogoUrl || '',
attesterAddress: checksumAddress(delegation.attesterAddress),
rollupAddress: checksumAddress(delegation.rollupAddress),
// See directStakeBreakdown's note: fast-path hint for unstake routing.
moveWithRollup: delegation.moveWithRollup,
effectiveRollup: checksumAddress(delegation.effectiveRollup),
stakedAmount: delegation.stakedAmount.toString(),
splitContract: checksumAddress(delegation.splitContractAddress),
providerTakeRate: delegation.providerTakeRate,
Expand All @@ -177,6 +187,9 @@ export async function handleBeneficiaryStakingOverview(c: Context): Promise<Resp
providerLogo: metadata?.providerLogoUrl || '',
attesterAddress: checksumAddress(delegation.attesterAddress),
rollupAddress: checksumAddress(delegation.rollupAddress),
// See directStakeBreakdown's note: fast-path hint for unstake routing.
moveWithRollup: delegation.moveWithRollup,
effectiveRollup: checksumAddress(delegation.effectiveRollup),
stakedAmount: delegation.stakedAmount.toString(),
splitContract: checksumAddress(delegation.splitContractAddress),
providerTakeRate: delegation.providerTakeRate,
Expand All @@ -196,6 +209,14 @@ export async function handleBeneficiaryStakingOverview(c: Context): Promise<Resp
attesterAddress: checksumAddress(dep.attesterAddress),
withdrawerAddress: checksumAddress(dep.withdrawerAddress),
rollupAddress: checksumAddress(dep.rollupAddress),
// Fast-path hint for unstake routing. `deposit.moveWithRollup` is
// decoded from the originating tx's calldata at indexing time;
// `deposit.effectiveRollup` follows canonical migrations on
// `moveWithRollup = true` rows. Both columns are populated at
// insert by the deposit handler; the schema enforces non-null on
// `effectiveRollup`.
moveWithRollup: dep.moveWithRollup ?? null,
effectiveRollup: checksumAddress(dep.effectiveRollup),
stakedAmount: dep.amount.toString(),
txHash: dep.txHash,
timestamp: Number(dep.timestamp),
Expand Down
18 changes: 16 additions & 2 deletions atp-indexer/src/api/types/atp.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,22 @@

export type StakeStatus = 'SUCCESS' | 'FAILED' | 'PENDING' | 'UNSTAKED';

export interface ATPDirectStake {
/**
* Fields the indexer attaches as a fast-path hint for "where this stake
* currently lives". The dashboard short-circuits its on-chain probe when
* these are present. Optional for TS-consumer back-compat — older
* clients pre-dating these fields keep type-checking. See the matching
* type in `staking.types.ts`.
*/
interface EffectiveRollupFields {
moveWithRollup?: boolean | null;
effectiveRollup?: string;
}

export interface ATPDirectStake extends EffectiveRollupFields {
attesterAddress: string;
operatorAddress: string;
rollupAddress: string;
stakedAmount: string;
totalSlashed: string;
txHash: string;
Expand All @@ -18,11 +31,12 @@ export interface ATPDirectStake {
status: StakeStatus;
}

export interface ATPDelegation {
export interface ATPDelegation extends EffectiveRollupFields {
providerId: number;
providerName: string;
providerLogo: string;
operatorAddress: string;
rollupAddress: string;
stakedAmount: string;
totalSlashed: string;
splitContract: string;
Expand Down
35 changes: 31 additions & 4 deletions atp-indexer/src/api/types/staking.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,33 @@ export interface StakingSummaryResponse {
stats: StakingStats;
}

export interface DirectStakeBreakdown {
/**
* Fields common to every "this is where the stake currently lives" hint
* the indexer emits. The dashboard uses these to short-circuit its
* on-chain probe; null `moveWithRollup` means the indexer couldn't decode
* it and the dashboard should fall back to the probe.
*
* Both fields are optional in the response type. This is purely a
* TypeScript-consumer compatibility hedge: older clients pre-dating this
* field, or any future indexer regression that returns rows without the
* hint, both keep type-checking. The runtime payload from this indexer
* always sets them.
*/
interface EffectiveRollupFields {
/** Decoded from the originating tx's calldata. `null` if the entry
* point isn't a recognised stake function (future variants, manual
* contract interaction, etc.). */
moveWithRollup?: boolean | null;
/** The rollup currently believed to hold the live record. Tracks
* canonical migrations for `moveWithRollup = true` rows; equals
* `rollupAddress` otherwise. */
effectiveRollup?: string;
}

export interface DirectStakeBreakdown extends EffectiveRollupFields {
atpAddress: string;
attesterAddress: string;
rollupAddress: string;
stakedAmount: string;
hasFailedDeposit: boolean;
failedDepositTxHash: string | null;
Expand All @@ -40,12 +64,13 @@ export interface DirectStakeBreakdown {
providerLogo?: string;
}

export interface DelegationBreakdown {
export interface DelegationBreakdown extends EffectiveRollupFields {
atpAddress: string;
providerId: number;
providerName: string;
providerLogo: string;
attesterAddress: string;
rollupAddress: string;
stakedAmount: string;
splitContract: string;
providerTakeRate: number;
Expand All @@ -59,11 +84,12 @@ export interface DelegationBreakdown {
status: StakeStatus;
}

export interface Erc20DelegationBreakdown {
export interface Erc20DelegationBreakdown extends EffectiveRollupFields {
providerId: number;
providerName: string;
providerLogo: string;
attesterAddress: string;
rollupAddress: string;
stakedAmount: string;
splitContract: string;
providerTakeRate: number;
Expand All @@ -77,9 +103,10 @@ export interface Erc20DelegationBreakdown {
status: StakeStatus;
}

export interface Erc20DirectStakeBreakdown {
export interface Erc20DirectStakeBreakdown extends EffectiveRollupFields {
attesterAddress: string;
withdrawerAddress: string;
rollupAddress: string;
stakedAmount: string;
txHash: string;
timestamp: number;
Expand Down
Loading
Loading