diff --git a/packages/apps/ability-hyperliquid/src/lib/ability-helpers/approve-builder-fee.ts b/packages/apps/ability-hyperliquid/src/lib/ability-helpers/approve-builder-fee.ts new file mode 100644 index 000000000..bf716394c --- /dev/null +++ b/packages/apps/ability-hyperliquid/src/lib/ability-helpers/approve-builder-fee.ts @@ -0,0 +1,30 @@ +import * as hyperliquid from '@nktkas/hyperliquid'; +import { approveBuilderFee, SuccessResponse } from '@nktkas/hyperliquid/api/exchange'; +import { LitActionPkpEthersWallet } from './lit-action-pkp-ethers-wallet'; +import { DEFAULT_BUILDER } from '../constants'; + +export async function approveBuilderFeeAction({ + transport, + pkpPublicKey, + useTestnet = false, +}: { + transport: hyperliquid.HttpTransport; + pkpPublicKey: string; + useTestnet?: boolean; +}): Promise { + const pkpWallet = new LitActionPkpEthersWallet(pkpPublicKey); + + const response = await Lit.Actions.runOnce( + { waitForResponse: true, name: 'HyperLiquidApproveBuilderFee' }, + async () => { + return JSON.stringify( + await approveBuilderFee( + { transport, wallet: pkpWallet }, + { builder: DEFAULT_BUILDER.address, maxFeeRate: DEFAULT_BUILDER.maxFeeRate }, + ), + ); + }, + ); + + return JSON.parse(response) as SuccessResponse; +} diff --git a/packages/apps/ability-hyperliquid/src/lib/ability-helpers/execute-perp-order.ts b/packages/apps/ability-hyperliquid/src/lib/ability-helpers/execute-perp-order.ts index c1affb57e..db33d887f 100644 --- a/packages/apps/ability-hyperliquid/src/lib/ability-helpers/execute-perp-order.ts +++ b/packages/apps/ability-hyperliquid/src/lib/ability-helpers/execute-perp-order.ts @@ -10,6 +10,7 @@ import { signL1Action } from '@nktkas/hyperliquid/signing'; import { bigIntReplacer } from '@lit-protocol/vincent-ability-sdk'; import { LitActionPkpEthersWallet } from './lit-action-pkp-ethers-wallet'; +import { DEFAULT_BUILDER } from '../constants'; export type TimeInForce = 'Gtc' | 'Ioc' | 'Alo'; @@ -140,6 +141,8 @@ export async function executePerpOrder({ ? { limit: { tif: 'FrontendMarket' } } : { limit: { tif: orderType.tif } }; + const builderConfig = DEFAULT_BUILDER; + // Construct order action const orderAction = parser(OrderRequest.entries.action)({ type: 'order', @@ -151,6 +154,10 @@ export async function executePerpOrder({ s: params.size, r: params.reduceOnly ?? false, // reduce only (true to close positions, false for opening) t: orderTypeField, + builder: { + b: builderConfig.address, + f: builderConfig.fee, + }, }, ], grouping: 'na', diff --git a/packages/apps/ability-hyperliquid/src/lib/ability-helpers/execute-spot-order.ts b/packages/apps/ability-hyperliquid/src/lib/ability-helpers/execute-spot-order.ts index f9c24e012..fe8ffa42c 100644 --- a/packages/apps/ability-hyperliquid/src/lib/ability-helpers/execute-spot-order.ts +++ b/packages/apps/ability-hyperliquid/src/lib/ability-helpers/execute-spot-order.ts @@ -5,6 +5,7 @@ import { signL1Action } from '@nktkas/hyperliquid/signing'; import { bigIntReplacer } from '@lit-protocol/vincent-ability-sdk'; import { LitActionPkpEthersWallet } from './lit-action-pkp-ethers-wallet'; +import { DEFAULT_BUILDER } from '../constants'; export type TimeInForce = 'Gtc' | 'Ioc' | 'Alo'; @@ -77,6 +78,8 @@ export async function executeSpotOrder({ ? { limit: { tif: 'FrontendMarket' } } : { limit: { tif: orderType.tif } }; + const builderConfig = DEFAULT_BUILDER; + // Construct order action const orderAction = parser(OrderRequest.entries.action)({ type: 'order', @@ -88,6 +91,10 @@ export async function executeSpotOrder({ s: params.size, r: false, // reduce only (false for spot) t: orderTypeField, + builder: { + b: builderConfig.address, + f: builderConfig.fee, + }, }, ], grouping: 'na', diff --git a/packages/apps/ability-hyperliquid/src/lib/ability-helpers/index.ts b/packages/apps/ability-hyperliquid/src/lib/ability-helpers/index.ts index d27f7aa51..3d95b8ae2 100644 --- a/packages/apps/ability-hyperliquid/src/lib/ability-helpers/index.ts +++ b/packages/apps/ability-hyperliquid/src/lib/ability-helpers/index.ts @@ -5,3 +5,4 @@ export { sendDepositTx } from './send-deposit-tx'; export { transferUsdcTo } from './transfer-usdc-to'; export { executeSpotOrder } from './execute-spot-order'; export { executePerpOrder } from './execute-perp-order'; +export { approveBuilderFeeAction } from './approve-builder-fee'; diff --git a/packages/apps/ability-hyperliquid/src/lib/constants.ts b/packages/apps/ability-hyperliquid/src/lib/constants.ts new file mode 100644 index 000000000..940a63688 --- /dev/null +++ b/packages/apps/ability-hyperliquid/src/lib/constants.ts @@ -0,0 +1,6 @@ +export const DEFAULT_BUILDER = { + address: '0x132Db5f531Ba38628F1640683354229daE04E8e6', + /** 0.05% expressed in 0.1 bps units (500 * 0.0001% = 0.05%). */ + fee: 500, + maxFeeRate: '0.05%', +}; diff --git a/packages/apps/ability-hyperliquid/src/lib/schemas.ts b/packages/apps/ability-hyperliquid/src/lib/schemas.ts index c174ededd..d2c8d0202 100644 --- a/packages/apps/ability-hyperliquid/src/lib/schemas.ts +++ b/packages/apps/ability-hyperliquid/src/lib/schemas.ts @@ -10,6 +10,7 @@ export const actionTypeSchema = z.enum([ 'perpShort', 'cancelOrder', 'cancelAllOrdersForSymbol', + 'approveBuilder', ]); export const depositParamsSchema = z.object({ @@ -153,6 +154,7 @@ export const abilityParamsSchema = z if (data.action === 'perpLong' || data.action === 'perpShort') return !!data.perp; if (data.action === 'cancelOrder') return !!data.cancelOrder; if (data.action === 'cancelAllOrdersForSymbol') return !!data.cancelAllOrdersForSymbol; + if (data.action === 'approveBuilder') return true; return false; }, { @@ -196,4 +198,8 @@ export const executeSuccessSchema = z.object({ .any() .optional() .describe('Cancel result (for spotCancelOrder/spotCancelAll action)'), + builderApproval: z + .any() + .optional() + .describe('Builder approval result (for approveBuilder action)'), }); diff --git a/packages/apps/ability-hyperliquid/src/lib/types.ts b/packages/apps/ability-hyperliquid/src/lib/types.ts index 95a7f5c8a..a119f8599 100644 --- a/packages/apps/ability-hyperliquid/src/lib/types.ts +++ b/packages/apps/ability-hyperliquid/src/lib/types.ts @@ -11,6 +11,7 @@ export enum HyperliquidAction { PERP_SHORT = 'perpShort', CANCEL_ORDER = 'cancelOrder', CANCEL_ALL_ORDERS_FOR_SYMBOL = 'cancelAllOrdersForSymbol', + APPROVE_BUILDER = 'approveBuilder', } /** diff --git a/packages/apps/ability-hyperliquid/src/lib/vincent-ability.ts b/packages/apps/ability-hyperliquid/src/lib/vincent-ability.ts index b817ad6a6..f785b019b 100644 --- a/packages/apps/ability-hyperliquid/src/lib/vincent-ability.ts +++ b/packages/apps/ability-hyperliquid/src/lib/vincent-ability.ts @@ -28,6 +28,7 @@ import { cancelOrder, cancelAllOrdersForSymbol, executePerpOrder, + approveBuilderFeeAction, } from './ability-helpers'; import { depositPrechecks, @@ -227,6 +228,10 @@ export const vincentAbility = createVincentAbility({ return succeed({ action }); } + case HyperliquidAction.APPROVE_BUILDER: { + return succeed({ action }); + } + default: return fail({ action, reason: `Unknown action: ${action}` }); } @@ -441,6 +446,19 @@ export const vincentAbility = createVincentAbility({ }); } + case HyperliquidAction.APPROVE_BUILDER: { + const result = await approveBuilderFeeAction({ + transport, + pkpPublicKey: delegatorPkpInfo.publicKey, + useTestnet, + }); + + return succeed({ + action, + builderApproval: result, + }); + } + default: return fail({ action, reason: `Unknown action: ${action}` }); }