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
16 changes: 15 additions & 1 deletion core/src/exchanges/hyperliquid/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,13 +250,27 @@ export class HyperliquidExchange extends PredictionMarketExchange {
: { limit: { tif: 'Gtc' } },
};

// Key order matters for msgpack hash: type, orders, grouping
// Key order matters for msgpack hash: type, orders, grouping, builder
const action: Record<string, unknown> = {
type: 'order',
orders: [orderWire],
grouping: 'na',
};

if (params.builder !== undefined || params.builderFee !== undefined) {
if (!params.builder) {
throw new Error('Hyperliquid builderFee requires builder address');
}
if (!/^0x[0-9a-fA-F]{40}$/.test(params.builder)) {
throw new Error(`Invalid Hyperliquid builder address: ${params.builder}`);
}
const builderFee = params.builderFee ?? 0;
if (!Number.isInteger(builderFee) || builderFee < 0) {
throw new Error('Hyperliquid builderFee must be a non-negative integer in tenths of a basis point');
}
action.builder = { b: params.builder.toLowerCase(), f: builderFee };
}

return {
exchange: this.name,
params,
Expand Down
6 changes: 6 additions & 0 deletions core/src/server/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3992,6 +3992,12 @@ components:
fee:
type: number
description: 'Optional fee rate (e.g., 1000 for 0.1%)'
builder:
type: string
description: Hyperliquid builder address to attach to the order action.
builderFee:
type: number
description: Hyperliquid builder fee in tenths of a basis point (e.g. 10 = 1 bp).
tickSize:
type: number
description: Optional override for Limitless/Polymarket
Expand Down
4 changes: 4 additions & 0 deletions core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,10 @@ export interface CreateOrderParams {
denom?: 'usdc' | 'shares'; // Hosted mode: amount unit.
slippage_pct?: number; // Hosted mode: maximum market-order slippage percentage.
fee?: number; // Optional fee rate (e.g., 1000 for 0.1%)
/** Hyperliquid builder address to attach to the order action. */
builder?: string;
/** Hyperliquid builder fee in tenths of a basis point (e.g. 10 = 1 bp). */
builderFee?: number;
tickSize?: number; // Optional override for Limitless/Polymarket
negRisk?: boolean; // Optional override to skip neg-risk lookup (Polymarket)
onBehalfOf?: number; // Limitless delegated signing: profile ID to trade on behalf of
Expand Down
54 changes: 54 additions & 0 deletions core/test/exchanges/hyperliquid-build-order.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { HyperliquidExchange } from '../../src/exchanges/hyperliquid';

describe('HyperliquidExchange buildOrder builder attribution', () => {
const params = {
marketId: 'hl:#100001751',
outcomeId: '100001751',
side: 'buy' as const,
type: 'limit' as const,
amount: 10,
price: 0.001,
};

it('attaches builder attribution when builder params are supplied', async () => {
const exchange = new HyperliquidExchange({ testnet: true });
const built = await exchange.buildOrder({
...params,
builder: '0x370a6D37911294ebE8D45419d007E7e0C4BEC2a9',
builderFee: 10,
});

expect(built.raw).toEqual({
type: 'order',
orders: [{
a: 100001751,
b: true,
p: '0.001',
s: '10',
r: false,
t: { limit: { tif: 'Gtc' } },
}],
grouping: 'na',
builder: {
b: '0x370a6d37911294ebe8d45419d007e7e0c4bec2a9',
f: 10,
},
});
});

it('rejects malformed builder params before signing', async () => {
const exchange = new HyperliquidExchange({ testnet: true });

await expect(exchange.buildOrder({ ...params, builderFee: 10 })).rejects.toThrow(
'Hyperliquid builderFee requires builder address',
);
await expect(exchange.buildOrder({ ...params, builder: '0x123', builderFee: 10 })).rejects.toThrow(
'Invalid Hyperliquid builder address',
);
await expect(exchange.buildOrder({
...params,
builder: '0x370a6D37911294ebE8D45419d007E7e0C4BEC2a9',
builderFee: 0.5,
})).rejects.toThrow('Hyperliquid builderFee must be a non-negative integer');
});
});
8 changes: 8 additions & 0 deletions docs/api-reference/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -9909,6 +9909,14 @@
"type": "number",
"description": "Optional fee rate (e.g., 1000 for 0.1%)"
},
"builder": {
"type": "string",
"description": "Hyperliquid builder address to attach to the order action."
},
"builderFee": {
"type": "number",
"description": "Hyperliquid builder fee in tenths of a basis point (e.g. 10 = 1 bp)."
},
"tickSize": {
"type": "number",
"description": "Optional override for Limitless/Polymarket"
Expand Down
2 changes: 2 additions & 0 deletions sdks/python/API_REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2274,6 +2274,8 @@ price: float # Required for limit orders
denom: str # Hosted mode: amount unit.
slippage_pct: float # Hosted mode: maximum market-order slippage percentage.
fee: float # Optional fee rate (e.g., 1000 for 0.1%)
builder: str # Hyperliquid builder address to attach to the order action.
builder_fee: float # Hyperliquid builder fee in tenths of a basis point (e.g. 10 = 1 bp).
tick_size: float # Optional override for Limitless/Polymarket
neg_risk: bool # Optional override to skip neg-risk lookup (Polymarket)
on_behalf_of: float # Limitless delegated signing: profile ID to trade on behalf of
Expand Down
2 changes: 2 additions & 0 deletions sdks/typescript/API_REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2269,6 +2269,8 @@ price?: number; // Required for limit orders
denom?: string; // Hosted mode: amount unit.
slippage_pct?: number; // Hosted mode: maximum market-order slippage percentage.
fee?: number; // Optional fee rate (e.g., 1000 for 0.1%)
builder?: string; // Hyperliquid builder address to attach to the order action.
builderFee?: number; // Hyperliquid builder fee in tenths of a basis point (e.g. 10 = 1 bp).
tickSize?: number; // Optional override for Limitless/Polymarket
negRisk?: boolean; // Optional override to skip neg-risk lookup (Polymarket)
onBehalfOf?: number; // Limitless delegated signing: profile ID to trade on behalf of
Expand Down