Skip to content
Open
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ Phase 2 implements the observation and persistence path:
- `repositories/vault-repository.ts` upserts vault metadata and appends decoded events, deduplicating on the Soroban event id so a replay is idempotent.
- `config.ts` reads the RPC, contract, and Supabase configuration.

Still planned: a separate processor/handler split, reconciliation, and stronger replay guarantees. The watcher also retains a scaffold-only `pool_snapshots` write that the existing API route and dashboard still consume; replacing it with real vault state requires contract state reads (Phase 5).
Still planned: a separate processor/handler split, reconciliation, and stronger replay guarantees. Retained scaffold `pool_snapshots` writes of randomly generated TVL and APY have been removed in accordance with the project's "no fake implementations" rule; real vault statistics will be populated once contract state reads and NAV feeds are wired in Phase 5.

## Frontend Architecture

Expand Down
21 changes: 0 additions & 21 deletions services/indexer/src/watcher.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type { SupabaseClient } from '@supabase/supabase-js';
import { Server, type Api } from '@stellar/stellar-sdk/rpc';
import {
DATABASE_TABLES,
INDEXER_DEFAULTS,
INDEXER_EVENTS_STREAM,
} from '@yieldanchor/constants';
Expand Down Expand Up @@ -68,23 +67,6 @@ async function projectEvents(
await insertVaultEvents(supabase, events);
}

/**
* Scaffold-only behaviour retained from the Phase 0 poller: the read API and
* web dashboard still consume `pool_snapshots`. Replacing this with real vault
* state requires contract state reads, which are Phase 5 work.
*/
async function recordScaffoldSnapshot(supabase: SupabaseClient): Promise<void> {
const tvl = Math.floor(Math.random() * 10_000_000) / 100;
const dynamicApy = (5 + Math.random() * 5).toFixed(2);
await supabase.from(DATABASE_TABLES.poolSnapshots).insert([
{
tvl,
dynamic_apy: Number(dynamicApy),
timestamp: new Date().toISOString(),
},
]);
}

export async function startWatcher(): Promise<void> {
const config = loadConfig();
const supabase = createSupabaseClient(config);
Expand Down Expand Up @@ -172,9 +154,6 @@ export async function startWatcher(): Promise<void> {
);
}

if (supabase) {
await recordScaffoldSnapshot(supabase);
}
} catch (error) {
console.error('Poller error', error);
} finally {
Expand Down
11 changes: 10 additions & 1 deletion services/indexer/test/watcher.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {

const mocks = vi.hoisted(() => ({
hasDatabase: false,
fromSpy: vi.fn(),
getEvents: vi.fn(),
getLatestLedger: vi.fn(),
loadCheckpoint: vi.fn(),
Expand All @@ -31,7 +32,7 @@ vi.mock('../src/config.js', () => ({
loadConfig: () => ({ contractId: CONTRACT, rpcUrl: 'https://rpc.invalid' }),
createSupabaseClient: () =>
mocks.hasDatabase
? { from: () => ({ insert: async () => ({ error: null }) }) }
? { from: mocks.fromSpy }
: null,
}));

Expand Down Expand Up @@ -113,6 +114,7 @@ describe('watcher persistence logging', () => {
vi.spyOn(console, 'warn').mockImplementation(() => undefined);
vi.spyOn(console, 'error').mockImplementation(() => undefined);
mocks.hasDatabase = false;
mocks.fromSpy.mockReturnValue({ insert: vi.fn().mockResolvedValue({ error: null }) });
mocks.loadCheckpoint.mockResolvedValue(null);
mocks.saveCheckpoint.mockResolvedValue(undefined);
mocks.insertVaultEvents.mockResolvedValue(undefined);
Expand Down Expand Up @@ -183,4 +185,11 @@ describe('watcher persistence logging', () => {
);
expect(mocks.saveCheckpoint).not.toHaveBeenCalled();
});

it('does not write fabricated random snapshots to pool_snapshots', async () => {
mocks.hasDatabase = true;
await startWatcher();

expect(mocks.fromSpy).not.toHaveBeenCalledWith('pool_snapshots');
});
});