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
Original file line number Diff line number Diff line change
Expand Up @@ -204,25 +204,25 @@ const PerpetualDecreaseRequestBaseSchema = z.object({
side: PositionSideSchema,
});

const PerpetualDecreaseFullRequestSchema = PerpetualDecreaseRequestBaseSchema.extend({
const PerpetualDecreaseFullSchema = z.object({
mode: z.literal('full'),
full: z.object({
slippageBps: Base10IntegerStringSchema,
}),
slippageBps: Base10IntegerStringSchema,
});

const PerpetualDecreasePartialRequestSchema = PerpetualDecreaseRequestBaseSchema.extend({
const PerpetualDecreasePartialSchema = z.object({
mode: z.literal('partial'),
partial: z.object({
sizeDeltaUsd: Base10IntegerStringSchema,
slippageBps: Base10IntegerStringSchema,
}),
sizeDeltaUsd: Base10IntegerStringSchema,
slippageBps: Base10IntegerStringSchema,
});

export const CreatePerpetualsDecreaseQuoteRequestSchema = z.discriminatedUnion('mode', [
PerpetualDecreaseFullRequestSchema,
PerpetualDecreasePartialRequestSchema,
const PerpetualDecreaseSchema = z.discriminatedUnion('mode', [
PerpetualDecreaseFullSchema,
PerpetualDecreasePartialSchema,
]);

export const CreatePerpetualsDecreaseQuoteRequestSchema = PerpetualDecreaseRequestBaseSchema.extend({
decrease: PerpetualDecreaseSchema,
});
export type CreatePerpetualsDecreaseQuoteRequest = z.infer<
typeof CreatePerpetualsDecreaseQuoteRequestSchema
>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ import {
import * as perpetualSchemas from './perpetuals.js';

describe('CreatePerpetualsDecreaseQuoteRequestSchema', () => {
it('requires sizeDeltaUsd for partial mode', () => {
it('requires sizeDeltaUsd for nested partial decrease mode', () => {
const validPartial = CreatePerpetualsDecreaseQuoteRequestSchema.safeParse({
walletAddress: '0xabc',
providerName: 'gmx',
chainId: '42161',
marketAddress: '0xmarket',
collateralTokenAddress: '0xcollateral',
side: 'long',
mode: 'partial',
partial: {
decrease: {
mode: 'partial',
sizeDeltaUsd: '100000000',
slippageBps: '100',
},
Expand All @@ -32,15 +32,46 @@ describe('CreatePerpetualsDecreaseQuoteRequestSchema', () => {
marketAddress: '0xmarket',
collateralTokenAddress: '0xcollateral',
side: 'long',
mode: 'partial',
partial: {
decrease: {
mode: 'partial',
slippageBps: '100',
},
});

expect(validPartial.success).toBe(true);
expect(invalidPartial.success).toBe(false);
});

it('accepts nested full mode and rejects legacy top-level mode payload', () => {
const validFull = CreatePerpetualsDecreaseQuoteRequestSchema.safeParse({
walletAddress: '0xabc',
providerName: 'gmx',
chainId: '42161',
marketAddress: '0xmarket',
collateralTokenAddress: '0xcollateral',
side: 'short',
decrease: {
mode: 'full',
slippageBps: '100',
},
});

const legacyTopLevel = CreatePerpetualsDecreaseQuoteRequestSchema.safeParse({
walletAddress: '0xabc',
providerName: 'gmx',
chainId: '42161',
marketAddress: '0xmarket',
collateralTokenAddress: '0xcollateral',
side: 'short',
mode: 'full',
full: {
slippageBps: '100',
},
});

expect(validFull.success).toBe(true);
expect(legacyTopLevel.success).toBe(false);
});
});

describe('CreatePerpetualsIncreaseQuoteRequestSchema', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,14 @@ export namespace EndpointInterfaces {
perpetuals.PerpetualsCreatePositionRequestSchema;
export type PerpetualsCreatePositionRequest =
perpetuals.PerpetualsCreatePositionRequest;
export const CreatePerpetualsDecreaseQuoteRequestSchema =
perpetuals.CreatePerpetualsDecreaseQuoteRequestSchema;
export type CreatePerpetualsDecreaseQuoteRequest =
perpetuals.CreatePerpetualsDecreaseQuoteRequest;
export const CreatePerpetualsDecreasePlanRequestSchema =
perpetuals.CreatePerpetualsDecreasePlanRequestSchema;
export type CreatePerpetualsDecreasePlanRequest =
perpetuals.CreatePerpetualsDecreasePlanRequest;
export const PerpetualsPositionPromptSchema =
perpetuals.PerpetualsPositionPromptSchema;
export const PossiblePerpetualPositionsRequestSchema =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { z } from 'zod';

import { PositionSideSchema } from '../core/schemas/perpetuals.js';
import {
CreatePerpetualsDecreasePlanRequestSchema as CoreCreatePerpetualsDecreasePlanRequestSchema,
CreatePerpetualsDecreaseQuoteRequestSchema as CoreCreatePerpetualsDecreaseQuoteRequestSchema,
PositionSideSchema,
} from '../core/schemas/perpetuals.js';

import {
PaginatedPossibleResultsRequestSchema,
Expand Down Expand Up @@ -29,6 +33,18 @@ export type PerpetualsCreatePositionRequest = z.infer<
typeof PerpetualsCreatePositionRequestSchema
>;

export const CreatePerpetualsDecreaseQuoteRequestSchema =
CoreCreatePerpetualsDecreaseQuoteRequestSchema;
export type CreatePerpetualsDecreaseQuoteRequest = z.infer<
typeof CreatePerpetualsDecreaseQuoteRequestSchema
>;

export const CreatePerpetualsDecreasePlanRequestSchema =
CoreCreatePerpetualsDecreasePlanRequestSchema;
export type CreatePerpetualsDecreasePlanRequest = z.infer<
typeof CreatePerpetualsDecreasePlanRequestSchema
>;

export const PerpetualsPositionPromptSchema = PerpetualsCreatePositionRequestSchema.pick({
chain: true,
market: true,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { describe, expect, it } from 'vitest';

import * as perpetualInterfaces from './perpetuals.js';

type SafeParseResult = { success: boolean };
type SafeParseSchema = { safeParse: (input: unknown) => SafeParseResult };

function getSchemaExport(schemaName: string): SafeParseSchema {
const candidate = (perpetualInterfaces as Record<string, unknown>)[schemaName];

expect(candidate).toBeDefined();

if (!candidate || typeof candidate !== 'object' || !('safeParse' in candidate)) {
throw new Error(`${schemaName} was not exported as a Zod schema`);
}

const schema = candidate as { safeParse: unknown };
if (typeof schema.safeParse !== 'function') {
throw new Error(`${schemaName} does not provide safeParse`);
}

return { safeParse: schema.safeParse as (input: unknown) => SafeParseResult };
}

describe('perpetual endpoint decrease request schemas', () => {
it('exports decrease quote and plan request schemas with nested decrease mode', () => {
const quoteSchema = getSchemaExport('CreatePerpetualsDecreaseQuoteRequestSchema');
const planSchema = getSchemaExport('CreatePerpetualsDecreasePlanRequestSchema');

const request = {
walletAddress: '0xabc',
providerName: 'gmx',
chainId: '42161',
marketAddress: '0xmarket',
collateralTokenAddress: '0xcollateral',
side: 'long',
decrease: {
mode: 'partial',
sizeDeltaUsd: '100000000',
slippageBps: '100',
},
};

expect(quoteSchema.safeParse(request).success).toBe(true);
expect(planSchema.safeParse(request).success).toBe(true);

const legacyRequest = {
walletAddress: '0xabc',
providerName: 'gmx',
chainId: '42161',
marketAddress: '0xmarket',
collateralTokenAddress: '0xcollateral',
side: 'long',
mode: 'partial',
partial: {
sizeDeltaUsd: '100000000',
slippageBps: '100',
},
};

expect(quoteSchema.safeParse(legacyRequest).success).toBe(false);
expect(planSchema.safeParse(legacyRequest).success).toBe(false);
});
});
55 changes: 55 additions & 0 deletions typescript/tests/setup/vitest.base.setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { afterAll, beforeAll } from 'vitest';

beforeAll(() => {
process.env['NODE_ENV'] = 'test';

const logLevel = process.env['LOG_LEVEL'] || 'none';

if (logLevel !== 'debug') {
global.originalConsole = {
log: console.log,
error: console.error,
warn: console.warn,
debug: console.debug,
};

switch (logLevel) {
case 'error':
console.log = () => {};
console.warn = () => {};
console.debug = () => {};
break;
case 'warn':
console.log = () => {};
console.debug = () => {};
break;
case 'none':
default:
console.log = () => {};
console.error = () => {};
console.warn = () => {};
console.debug = () => {};
break;
}
}
});

afterAll(() => {
if (global.originalConsole) {
console.log = global.originalConsole.log;
console.error = global.originalConsole.error;
console.warn = global.originalConsole.warn;
console.debug = global.originalConsole.debug;
}
});

declare global {
var originalConsole:
| {
log: typeof console.log;
error: typeof console.error;
warn: typeof console.warn;
debug: typeof console.debug;
}
| undefined;
}
1 change: 1 addition & 0 deletions typescript/tests/setup/vitest.setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import './vitest.base.setup.js';