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
1 change: 1 addition & 0 deletions src/config.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ export const envSchema = z
.int()
.positive()
.default(1000),

})
.superRefine((data, ctx) => {
if (data.MODE === 'production' && data.STELLAR_NETWORK === 'testnet') {
Expand Down
1 change: 1 addition & 0 deletions src/constants/error.constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@
*/
export const ErrorCode = {
VALIDATION_ERROR: 'VALIDATION_ERROR',
UNPROCESSABLE_ENTITY: 'UNPROCESSABLE_ENTITY',
NOT_FOUND: 'NOT_FOUND',
UNAUTHORIZED: 'UNAUTHORIZED',
FORBIDDEN: 'FORBIDDEN',
CONFLICT: 'CONFLICT',
BAD_REQUEST: 'BAD_REQUEST',
UNPROCESSABLE_ENTITY: 'UNPROCESSABLE_ENTITY',

Check failure on line 13 in src/constants/error.constants.ts

View workflow job for this annotation

GitHub Actions / verify

An object literal cannot have multiple properties with the same name.
INTERNAL_ERROR: 'INTERNAL_ERROR',
RATE_LIMIT: 'RATE_LIMIT',
PRISMA_ERROR: 'DATABASE_ERROR',
Expand Down
4 changes: 3 additions & 1 deletion src/modules/creator/creator.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,11 @@
'capBps must be between 100 and 2500'
);
return;
}
} const keyId = Array.isArray(req.params.keyId)

Check failure on line 77 in src/modules/creator/creator.routes.ts

View workflow job for this annotation

GitHub Actions / verify

Cannot redeclare block-scoped variable 'keyId'.
? req.params.keyId[0]
: req.params.keyId;

const keyId = Array.isArray(req.params.keyId)

Check failure on line 81 in src/modules/creator/creator.routes.ts

View workflow job for this annotation

GitHub Actions / verify

Cannot redeclare block-scoped variable 'keyId'.
? req.params.keyId[0]
: req.params.keyId;
try {
Expand Down
67 changes: 67 additions & 0 deletions src/modules/indexer/price-snapshot-debug-log.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ jest.mock('../../utils/prisma.utils', () => ({
create: jest.fn(),
update: jest.fn(),
},
creatorPriceHistory: {
create: jest.fn(),
},
},
}));

Expand All @@ -34,6 +37,9 @@ const mockPrisma = prisma as unknown as {
create: jest.Mock;
update: jest.Mock;
};
creatorPriceHistory: {
create: jest.Mock;
};
};

const mockLogger = logger as unknown as {
Expand Down Expand Up @@ -89,6 +95,67 @@ describe('#636 price snapshot write debug log', () => {
expect(fields.previous_price).toBeNull();
});

it('skips snapshot and history writes when the price is unchanged', async () => {
mockPrisma.creatorPriceSnapshot.findUnique.mockResolvedValue({
creatorId: CREATOR_ID,
currentPrice: BigInt(1_000_000),
price24hAgo: BigInt(900_000),
lastTradeAt: new Date('2026-01-01T00:00:00Z'),
});

await upsertPriceSnapshot({
creatorId: CREATOR_ID,
price: BigInt(1_000_000),
tradeAt: new Date('2026-01-02T00:00:00Z'),
});

expect(mockPrisma.creatorPriceSnapshot.update).not.toHaveBeenCalled();
expect(mockPrisma.creatorPriceHistory.create).not.toHaveBeenCalled();
});

it('writes a new snapshot and history record when the price changes', async () => {
mockPrisma.creatorPriceSnapshot.findUnique.mockResolvedValue({
creatorId: CREATOR_ID,
currentPrice: BigInt(1_000_000),
price24hAgo: BigInt(900_000),
lastTradeAt: new Date('2026-01-01T00:00:00Z'),
});
mockPrisma.creatorPriceSnapshot.update.mockResolvedValue({});
mockPrisma.creatorPriceHistory.create.mockResolvedValue({});

const tradeAt = new Date('2026-01-02T00:00:00Z');
await upsertPriceSnapshot({
creatorId: CREATOR_ID,
price: BigInt(1_100_000),
tradeAt,
});

expect(mockPrisma.creatorPriceSnapshot.update).toHaveBeenCalledTimes(1);
expect(mockPrisma.creatorPriceHistory.create).toHaveBeenCalledTimes(1);
expect(mockPrisma.creatorPriceHistory.create).toHaveBeenCalledWith({
data: {
creatorId: CREATOR_ID,
price: BigInt(1_100_000),
recordedAt: tradeAt,
},
});
});

it('writes the first snapshot when no previous snapshot exists', async () => {
mockPrisma.creatorPriceSnapshot.findUnique.mockResolvedValue(null);
mockPrisma.creatorPriceSnapshot.create.mockResolvedValue({});
mockPrisma.creatorPriceHistory.create.mockResolvedValue({});

await upsertPriceSnapshot({
creatorId: CREATOR_ID,
price: BigInt(1_000_000),
tradeAt: new Date('2026-01-01T00:00:00Z'),
});

expect(mockPrisma.creatorPriceSnapshot.create).toHaveBeenCalledTimes(1);
expect(mockPrisma.creatorPriceHistory.create).toHaveBeenCalledTimes(1);
});

it('emits a debug log with the previous price on a subsequent (update) write', async () => {
mockPrisma.creatorPriceSnapshot.findUnique.mockResolvedValue({
creatorId: CREATOR_ID,
Expand Down
Loading