Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
642fbc3
refactor(HyperLiquidProvider): enhance caching and error handling for…
abretonc7s Nov 6, 2025
c1d380b
Merge remote-tracking branch 'origin/main' into fix/perps/session-cac…
abretonc7s Nov 6, 2025
69188e8
bugbot
abretonc7s Nov 6, 2025
dec4128
refactor(HyperLiquidProvider): improve referral setup and error handling
abretonc7s Nov 6, 2025
6256b10
Merge remote-tracking branch 'origin/main' into fix/perps/session-cac…
abretonc7s Nov 6, 2025
97e1c2a
refactor(HyperLiquidProvider): enhance referral and builder fee appro…
abretonc7s Nov 6, 2025
965e652
Merge branch 'main' into fix/perps/session-caching
abretonc7s Nov 6, 2025
ad28847
refactor(HyperLiquidProvider): improve referral caching logic
abretonc7s Nov 6, 2025
15a5540
Merge branch 'main' into fix/perps/session-caching
abretonc7s Nov 6, 2025
4dd65a2
fix: pr comments
abretonc7s Nov 6, 2025
2207588
Merge branch 'main' into fix/perps/session-caching
abretonc7s Nov 6, 2025
48fdd3b
Merge branch 'main' into fix/perps/session-caching
abretonc7s Nov 6, 2025
fe2ed58
Merge branch 'main' into fix/perps/session-caching
abretonc7s Nov 7, 2025
0e4a2d9
Merge branch 'main' into fix/perps/session-caching
abretonc7s Nov 7, 2025
27fd76e
Merge branch 'main' into fix/perps/session-caching
abretonc7s Nov 7, 2025
9cde3e2
Merge branch 'main' into fix/perps/session-caching
abretonc7s Nov 8, 2025
8a8d794
Merge branch 'main' into fix/perps/session-caching
abretonc7s Nov 10, 2025
4236683
fix: upgrade hyperliquid sdk
abretonc7s Nov 10, 2025
285492d
feat: force rest api instead of websocket for write calls
abretonc7s Nov 10, 2025
692c64d
Merge remote-tracking branch 'origin/main' into fix/perps/session-cac…
abretonc7s Nov 10, 2025
bd40f8c
feat: enhance HyperLiquidClientService reconnect options
abretonc7s Nov 10, 2025
4d11e85
Merge branch 'main' into fix/perps/session-caching
abretonc7s Nov 10, 2025
8ab5b42
Merge branch 'main' into fix/perps/session-caching
abretonc7s Nov 10, 2025
acd98e5
Merge branch 'main' into fix/perps/session-caching
abretonc7s Nov 10, 2025
1e66543
Merge branch 'main' into fix/perps/session-caching
nickewansmith Nov 10, 2025
b85d046
Merge branch 'main' into fix/perps/session-caching
nickewansmith Nov 10, 2025
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 @@ -2616,7 +2616,7 @@ describe('HyperLiquidProvider', () => {
const result = await provider.updatePositionTPSL(updateParams);

expect(result.success).toBe(false);
expect(result.error).toContain('Failed to fetch market metadata');
expect(result.error).toContain('Invalid meta response');
});

it('should handle meta response without universe property', async () => {
Expand All @@ -2634,7 +2634,7 @@ describe('HyperLiquidProvider', () => {
const result = await provider.updatePositionTPSL(updateParams);

expect(result.success).toBe(false);
expect(result.error).toContain('Failed to fetch market metadata');
expect(result.error).toContain('Invalid meta response');
});
});

Expand Down Expand Up @@ -4266,20 +4266,27 @@ describe('HyperLiquidProvider', () => {

expect(result.success).toBe(true);

// Verify builder fee approval was called
// Builder fee approval is set once during ensureReady() initialization
// With session caching, it should be called once (during first ensureReady)
expect(
mockClientService.getExchangeClient().approveBuilderFee,
).toHaveBeenCalledWith({
builder: expect.any(String),
maxFeeRate: expect.stringContaining('%'),
});

// Verify referral code was set
expect(
mockClientService.getExchangeClient().setReferrer,
).toHaveBeenCalledWith({
code: expect.any(String),
});
// Note: Referral setup is fire-and-forget (non-blocking), so we can't reliably
// test it synchronously. It's tested separately in dedicated referral tests.

// Place a second order to verify caching (should NOT call builder fee approval again)
const mockExchangeClient = mockClientService.getExchangeClient();
(mockExchangeClient.approveBuilderFee as jest.Mock).mockClear();

const result2 = await provider.placeOrder(orderParams);

expect(result2.success).toBe(true);
// Session cache prevents redundant builder fee approval calls
expect(mockExchangeClient.approveBuilderFee).not.toHaveBeenCalled();

// Verify order was placed with builder fee
expect(mockClientService.getExchangeClient().order).toHaveBeenCalledWith(
Expand Down Expand Up @@ -4450,7 +4457,7 @@ describe('HyperLiquidProvider', () => {
expect(result.error).toContain('Builder fee approval failed');
});

it('should handle referral code setup failure', async () => {
it('should handle referral code setup failure (non-blocking)', async () => {
// Mock builder fee already approved
mockClientService.getInfoClient = jest
.fn()
Expand Down Expand Up @@ -4483,8 +4490,9 @@ describe('HyperLiquidProvider', () => {

const result = await provider.placeOrder(orderParams);

expect(result.success).toBe(false);
expect(result.error).toContain('Error ensuring referral code is set');
// Referral setup is now non-blocking (fire-and-forget), so order should succeed
expect(result.success).toBe(true);
expect(result.orderId).toBeDefined();
});

it('should skip referral setup when referral code is not ready', async () => {
Expand Down Expand Up @@ -4574,6 +4582,11 @@ describe('HyperLiquidProvider', () => {

it('should properly transform getOrders with reduceOnly and isTrigger fields', async () => {
mockClientService.getInfoClient = jest.fn().mockReturnValue({
maxBuilderFee: jest.fn().mockResolvedValue(1),
referral: jest.fn().mockResolvedValue({
referrerState: { stage: 'ready', data: { code: 'MMCSI' } },
referredBy: { code: 'MMCSI' },
}),
historicalOrders: jest.fn().mockResolvedValue([
{
order: {
Expand Down Expand Up @@ -4675,6 +4688,11 @@ describe('HyperLiquidProvider', () => {

it('should properly transform getOpenOrders with reduceOnly and isTrigger fields', async () => {
mockClientService.getInfoClient = jest.fn().mockReturnValue({
maxBuilderFee: jest.fn().mockResolvedValue(1),
referral: jest.fn().mockResolvedValue({
referrerState: { stage: 'ready', data: { code: 'MMCSI' } },
referredBy: { code: 'MMCSI' },
}),
clearinghouseState: jest.fn().mockResolvedValue({
marginSummary: { totalMarginUsed: '500', accountValue: '10500' },
withdrawable: '9500',
Expand Down Expand Up @@ -4993,6 +5011,11 @@ describe('HyperLiquidProvider', () => {
},
]);
mockClientService.getInfoClient = jest.fn().mockReturnValue({
maxBuilderFee: jest.fn().mockResolvedValue(1),
referral: jest.fn().mockResolvedValue({
referrerState: { stage: 'ready', data: { code: 'MMCSI' } },
referredBy: { code: 'MMCSI' },
}),
frontendOpenOrders: mockFrontendOpenOrders,
clearinghouseState: jest.fn().mockResolvedValue({
marginSummary: { totalMarginUsed: '0', accountValue: '1000' },
Expand Down Expand Up @@ -5073,6 +5096,11 @@ describe('HyperLiquidProvider', () => {
]);
});
mockClientService.getInfoClient = jest.fn().mockReturnValue({
maxBuilderFee: jest.fn().mockResolvedValue(1),
referral: jest.fn().mockResolvedValue({
referrerState: { stage: 'ready', data: { code: 'MMCSI' } },
referredBy: { code: 'MMCSI' },
}),
frontendOpenOrders: mockFrontendOpenOrders,
clearinghouseState: jest.fn().mockResolvedValue({
marginSummary: { totalMarginUsed: '0', accountValue: '1000' },
Expand Down
Loading
Loading