From 72c8d0205851a86116d4db2c39a74deae4ba5edc Mon Sep 17 00:00:00 2001 From: KevDydx Date: Tue, 25 Nov 2025 13:29:38 -0500 Subject: [PATCH] feat: dynamic leverage --- v4-client-js/src/clients/constants.ts | 1 + v4-client-js/src/clients/lib/registry.ts | 9 +++- v4-client-js/src/clients/modules/composer.ts | 48 +++++++++++++++----- v4-client-js/src/clients/modules/get.ts | 16 +++++++ v4-client-js/src/clients/modules/post.ts | 33 ++++++++++++++ 5 files changed, 93 insertions(+), 14 deletions(-) diff --git a/v4-client-js/src/clients/constants.ts b/v4-client-js/src/clients/constants.ts index 0d808c9a..8a4341ac 100644 --- a/v4-client-js/src/clients/constants.ts +++ b/v4-client-js/src/clients/constants.ts @@ -82,6 +82,7 @@ export const TYPE_URL_MSG_CANCEL_ORDER = '/dydxprotocol.clob.MsgCancelOrder'; export const TYPE_URL_BATCH_CANCEL = '/dydxprotocol.clob.MsgBatchCancel'; export const TYPE_URL_MSG_CREATE_CLOB_PAIR = '/dydxprotocol.clob.MsgCreateClobPair'; export const TYPE_URL_MSG_UPDATE_CLOB_PAIR = '/dydxprotocol.clob.MsgUpdateClobPair'; +export const TYPE_URL_MSG_UPDATE_LEVERAGE = '/dydxprotocol.clob.MsgUpdateLeverage'; // x/delaymsg export const TYPE_URL_MSG_DELAY_MESSAGE = '/dydxprotocol.delaymsg.MsgDelayMessage'; diff --git a/v4-client-js/src/clients/lib/registry.ts b/v4-client-js/src/clients/lib/registry.ts index 080d2a1a..6e1c846a 100644 --- a/v4-client-js/src/clients/lib/registry.ts +++ b/v4-client-js/src/clients/lib/registry.ts @@ -1,6 +1,9 @@ import { GeneratedType, Registry } from '@cosmjs/proto-signing'; import { defaultRegistryTypes } from '@cosmjs/stargate'; -import { MsgAddAuthenticator, MsgRemoveAuthenticator } from '@dydxprotocol/v4-proto/src/codegen/dydxprotocol/accountplus/tx'; +import { + MsgAddAuthenticator, + MsgRemoveAuthenticator, +} from '@dydxprotocol/v4-proto/src/codegen/dydxprotocol/accountplus/tx'; import { MsgRegisterAffiliate } from '@dydxprotocol/v4-proto/src/codegen/dydxprotocol/affiliates/tx'; import { MsgPlaceOrder, @@ -8,6 +11,7 @@ import { MsgCreateClobPair, MsgUpdateClobPair, MsgBatchCancel, + MsgUpdateLeverage, } from '@dydxprotocol/v4-proto/src/codegen/dydxprotocol/clob/tx'; import { MsgDelayMessage } from '@dydxprotocol/v4-proto/src/codegen/dydxprotocol/delaymsg/tx'; import { MsgCreateMarketPermissionless } from '@dydxprotocol/v4-proto/src/codegen/dydxprotocol/listing/tx'; @@ -41,6 +45,7 @@ import { TYPE_URL_MSG_CREATE_MARKET_PERMISSIONLESS, TYPE_URL_MSG_ADD_AUTHENTICATOR, TYPE_URL_MSG_REMOVE_AUTHENTICATOR, + TYPE_URL_MSG_UPDATE_LEVERAGE, } from '../constants'; export const registry: ReadonlyArray<[string, GeneratedType]> = []; @@ -52,6 +57,7 @@ export function generateRegistry(): Registry { [TYPE_URL_BATCH_CANCEL, MsgBatchCancel as GeneratedType], [TYPE_URL_MSG_CREATE_CLOB_PAIR, MsgCreateClobPair as GeneratedType], [TYPE_URL_MSG_UPDATE_CLOB_PAIR, MsgUpdateClobPair as GeneratedType], + [TYPE_URL_MSG_UPDATE_LEVERAGE, MsgUpdateLeverage as GeneratedType], // delaymsg [TYPE_URL_MSG_DELAY_MESSAGE, MsgDelayMessage as GeneratedType], @@ -77,7 +83,6 @@ export function generateRegistry(): Registry { // affiliates [TYPE_URL_MSG_REGISTER_AFFILIATE, MsgRegisterAffiliate as GeneratedType], - // authentication [TYPE_URL_MSG_ADD_AUTHENTICATOR, MsgAddAuthenticator as GeneratedType], [TYPE_URL_MSG_REMOVE_AUTHENTICATOR, MsgRemoveAuthenticator as GeneratedType], diff --git a/v4-client-js/src/clients/modules/composer.ts b/v4-client-js/src/clients/modules/composer.ts index c0cd3df5..e2ff58cd 100644 --- a/v4-client-js/src/clients/modules/composer.ts +++ b/v4-client-js/src/clients/modules/composer.ts @@ -7,13 +7,18 @@ import { MsgDelegate, MsgUndelegate, } from '@dydxprotocol/v4-proto/src/codegen/cosmos/staking/v1beta1/tx'; -import { MsgAddAuthenticator, MsgRemoveAuthenticator } from '@dydxprotocol/v4-proto/src/codegen/dydxprotocol/accountplus/tx'; +import { + MsgAddAuthenticator, + MsgRemoveAuthenticator, +} from '@dydxprotocol/v4-proto/src/codegen/dydxprotocol/accountplus/tx'; import { MsgRegisterAffiliate } from '@dydxprotocol/v4-proto/src/codegen/dydxprotocol/affiliates/tx'; import { ClobPair_Status } from '@dydxprotocol/v4-proto/src/codegen/dydxprotocol/clob/clob_pair'; import { + LeverageEntry, MsgBatchCancel, MsgCreateClobPair, MsgUpdateClobPair, + MsgUpdateLeverage, OrderBatch, } from '@dydxprotocol/v4-proto/src/codegen/dydxprotocol/clob/tx'; import { MsgDelayMessage } from '@dydxprotocol/v4-proto/src/codegen/dydxprotocol/delaymsg/tx'; @@ -56,6 +61,7 @@ import { TYPE_URL_MSG_ADD_AUTHENTICATOR, TYPE_URL_MSG_REMOVE_AUTHENTICATOR, AuthenticatorType, + TYPE_URL_MSG_UPDATE_LEVERAGE, } from '../constants'; import { DenomConfig, ITwapParameters, IBuilderCodeParameters } from '../types'; import { @@ -97,7 +103,7 @@ export class Composer { conditionalOrderTriggerSubticks: Long = Long.fromInt(0), twapParameters?: ITwapParameters, builderCodeParameters?: IBuilderCodeParameters, - orderRouterAddress: string = "", + orderRouterAddress: string = '', ): EncodeObject { this.validateGoodTilBlockAndTime(orderFlags, goodTilBlock, goodTilBlockTime); @@ -252,6 +258,27 @@ export class Composer { }; } + public composeMsgUpdateLeverage( + address: string, + subaccountNumber: number, + entries: LeverageEntry[], + ): EncodeObject { + const subaccountId: SubaccountId = { + owner: address, + number: subaccountNumber, + }; + + const msg: MsgUpdateLeverage = { + subaccountId, + clobPairLeverage: entries, + }; + + return { + typeUrl: TYPE_URL_MSG_UPDATE_LEVERAGE, + value: msg, + }; + } + // ------------ x/sending ------------ public composeMsgTransfer( address: string, @@ -577,13 +604,13 @@ export class Composer { const msg: MsgCreateMarketPermissionless = { ticker, - subaccountId + subaccountId, }; return { typeUrl: TYPE_URL_MSG_CREATE_MARKET_PERMISSIONLESS, value: msg, - } + }; } // ----------- x/accountplus -------- @@ -597,27 +624,24 @@ export class Composer { sender: address, authenticatorType, data, - } + }; return { typeUrl: TYPE_URL_MSG_ADD_AUTHENTICATOR, value: msg, - } + }; } - public composeMsgRemoveAuthenticator( - address: string, - id: Long, - ): EncodeObject { + public composeMsgRemoveAuthenticator(address: string, id: Long): EncodeObject { const msg: MsgRemoveAuthenticator = { sender: address, id, - } + }; return { typeUrl: TYPE_URL_MSG_REMOVE_AUTHENTICATOR, value: msg, - } + }; } // ------------ util ------------ diff --git a/v4-client-js/src/clients/modules/get.ts b/v4-client-js/src/clients/modules/get.ts index 02a81498..4f2f49b0 100644 --- a/v4-client-js/src/clients/modules/get.ts +++ b/v4-client-js/src/clients/modules/get.ts @@ -364,6 +364,22 @@ export class Get { return ClobModule.QueryEquityTierLimitConfigurationResponse.decode(data); } + /** + * @description Get user leverage settings for a given subaccount + * @returns User set leverage for all clob pairs + */ + async getPerpetualMarketsLeverage( + address: string, + subaccountNumber: number, + ): Promise { + const requestData: Uint8Array = Uint8Array.from( + ClobModule.QueryLeverageRequest.encode({ owner: address, number: subaccountNumber }).finish(), + ); + + const data: Uint8Array = await this.sendQuery('/dydxprotocol.clob.Query/Leverage', requestData); + return ClobModule.QueryLeverageResponse.decode(data); + } + /** * * @description Get all delegations from a delegator. diff --git a/v4-client-js/src/clients/modules/post.ts b/v4-client-js/src/clients/modules/post.ts index 1b3f971f..db011568 100644 --- a/v4-client-js/src/clients/modules/post.ts +++ b/v4-client-js/src/clients/modules/post.ts @@ -34,6 +34,7 @@ import { MsgCancelOrder, Order_ConditionType, OrderBatch, + LeverageEntry, } from './proto-includes'; // Required for encoding and decoding queries that are of type Long. @@ -628,6 +629,38 @@ export class Post { }); } + async updatePerpetualMarketsLeverage( + subaccount: SubaccountInfo, + address: string, + entries: LeverageEntry[], + broadcastMode?: BroadcastMode, + ): Promise { + const msg = await this.updatePerpetualMarketsLeverageMsg(subaccount, address, entries); + return this.send( + subaccount, + () => Promise.resolve([msg]), + false, + undefined, + undefined, + broadcastMode, + ); + } + + async updatePerpetualMarketsLeverageMsg( + subaccount: SubaccountInfo, + address: string, + entries: LeverageEntry[], + ): Promise { + return new Promise((resolve) => { + const msg = this.composer.composeMsgUpdateLeverage( + address, + subaccount.subaccountNumber, + entries, + ); + resolve(msg); + }); + } + async transfer( subaccount: SubaccountInfo, recipientAddress: string,