diff --git a/indexer/packages/v4-protos/src/codegen/dydxprotocol/bundle.ts b/indexer/packages/v4-protos/src/codegen/dydxprotocol/bundle.ts index 70819bb233..bf83b08c99 100644 --- a/indexer/packages/v4-protos/src/codegen/dydxprotocol/bundle.ts +++ b/indexer/packages/v4-protos/src/codegen/dydxprotocol/bundle.ts @@ -111,81 +111,82 @@ import * as _114 from "./stats/stats"; import * as _115 from "./stats/tx"; import * as _116 from "./subaccounts/asset_position"; import * as _117 from "./subaccounts/genesis"; -import * as _118 from "./subaccounts/perpetual_position"; -import * as _119 from "./subaccounts/query"; -import * as _120 from "./subaccounts/streaming"; -import * as _121 from "./subaccounts/subaccount"; -import * as _122 from "./vault/genesis"; -import * as _123 from "./vault/params"; -import * as _124 from "./vault/query"; -import * as _125 from "./vault/share"; -import * as _126 from "./vault/tx"; -import * as _127 from "./vault/vault"; -import * as _128 from "./vest/genesis"; -import * as _129 from "./vest/query"; -import * as _130 from "./vest/tx"; -import * as _131 from "./vest/vest_entry"; -import * as _139 from "./accountplus/query.lcd"; -import * as _140 from "./affiliates/query.lcd"; -import * as _141 from "./assets/query.lcd"; -import * as _142 from "./blocktime/query.lcd"; -import * as _143 from "./bridge/query.lcd"; -import * as _144 from "./clob/query.lcd"; -import * as _145 from "./delaymsg/query.lcd"; -import * as _146 from "./epochs/query.lcd"; -import * as _147 from "./feetiers/query.lcd"; -import * as _148 from "./listing/query.lcd"; -import * as _149 from "./perpetuals/query.lcd"; -import * as _150 from "./prices/query.lcd"; -import * as _151 from "./ratelimit/query.lcd"; -import * as _152 from "./revshare/query.lcd"; -import * as _153 from "./rewards/query.lcd"; -import * as _154 from "./stats/query.lcd"; -import * as _155 from "./subaccounts/query.lcd"; -import * as _156 from "./vault/query.lcd"; -import * as _157 from "./vest/query.lcd"; -import * as _158 from "./accountplus/query.rpc.Query"; -import * as _159 from "./affiliates/query.rpc.Query"; -import * as _160 from "./assets/query.rpc.Query"; -import * as _161 from "./blocktime/query.rpc.Query"; -import * as _162 from "./bridge/query.rpc.Query"; -import * as _163 from "./clob/query.rpc.Query"; -import * as _164 from "./delaymsg/query.rpc.Query"; -import * as _165 from "./epochs/query.rpc.Query"; -import * as _166 from "./feetiers/query.rpc.Query"; -import * as _167 from "./govplus/query.rpc.Query"; -import * as _168 from "./listing/query.rpc.Query"; -import * as _169 from "./perpetuals/query.rpc.Query"; -import * as _170 from "./prices/query.rpc.Query"; -import * as _171 from "./ratelimit/query.rpc.Query"; -import * as _172 from "./revshare/query.rpc.Query"; -import * as _173 from "./rewards/query.rpc.Query"; -import * as _174 from "./sending/query.rpc.Query"; -import * as _175 from "./stats/query.rpc.Query"; -import * as _176 from "./subaccounts/query.rpc.Query"; -import * as _177 from "./vault/query.rpc.Query"; -import * as _178 from "./vest/query.rpc.Query"; -import * as _179 from "./accountplus/tx.rpc.msg"; -import * as _180 from "./affiliates/tx.rpc.msg"; -import * as _181 from "./blocktime/tx.rpc.msg"; -import * as _182 from "./bridge/tx.rpc.msg"; -import * as _183 from "./clob/tx.rpc.msg"; -import * as _184 from "./delaymsg/tx.rpc.msg"; -import * as _185 from "./feetiers/tx.rpc.msg"; -import * as _186 from "./govplus/tx.rpc.msg"; -import * as _187 from "./listing/tx.rpc.msg"; -import * as _188 from "./perpetuals/tx.rpc.msg"; -import * as _189 from "./prices/tx.rpc.msg"; -import * as _190 from "./ratelimit/tx.rpc.msg"; -import * as _191 from "./revshare/tx.rpc.msg"; -import * as _192 from "./rewards/tx.rpc.msg"; -import * as _193 from "./sending/tx.rpc.msg"; -import * as _194 from "./stats/tx.rpc.msg"; -import * as _195 from "./vault/tx.rpc.msg"; -import * as _196 from "./vest/tx.rpc.msg"; -import * as _197 from "./lcd"; -import * as _198 from "./rpc.query"; -import * as _199 from "./rpc.tx"; +import * as _118 from "./subaccounts/leverage"; +import * as _119 from "./subaccounts/perpetual_position"; +import * as _120 from "./subaccounts/query"; +import * as _121 from "./subaccounts/streaming"; +import * as _122 from "./subaccounts/subaccount"; +import * as _123 from "./vault/genesis"; +import * as _124 from "./vault/params"; +import * as _125 from "./vault/query"; +import * as _126 from "./vault/share"; +import * as _127 from "./vault/tx"; +import * as _128 from "./vault/vault"; +import * as _129 from "./vest/genesis"; +import * as _130 from "./vest/query"; +import * as _131 from "./vest/tx"; +import * as _132 from "./vest/vest_entry"; +import * as _140 from "./accountplus/query.lcd"; +import * as _141 from "./affiliates/query.lcd"; +import * as _142 from "./assets/query.lcd"; +import * as _143 from "./blocktime/query.lcd"; +import * as _144 from "./bridge/query.lcd"; +import * as _145 from "./clob/query.lcd"; +import * as _146 from "./delaymsg/query.lcd"; +import * as _147 from "./epochs/query.lcd"; +import * as _148 from "./feetiers/query.lcd"; +import * as _149 from "./listing/query.lcd"; +import * as _150 from "./perpetuals/query.lcd"; +import * as _151 from "./prices/query.lcd"; +import * as _152 from "./ratelimit/query.lcd"; +import * as _153 from "./revshare/query.lcd"; +import * as _154 from "./rewards/query.lcd"; +import * as _155 from "./stats/query.lcd"; +import * as _156 from "./subaccounts/query.lcd"; +import * as _157 from "./vault/query.lcd"; +import * as _158 from "./vest/query.lcd"; +import * as _159 from "./accountplus/query.rpc.Query"; +import * as _160 from "./affiliates/query.rpc.Query"; +import * as _161 from "./assets/query.rpc.Query"; +import * as _162 from "./blocktime/query.rpc.Query"; +import * as _163 from "./bridge/query.rpc.Query"; +import * as _164 from "./clob/query.rpc.Query"; +import * as _165 from "./delaymsg/query.rpc.Query"; +import * as _166 from "./epochs/query.rpc.Query"; +import * as _167 from "./feetiers/query.rpc.Query"; +import * as _168 from "./govplus/query.rpc.Query"; +import * as _169 from "./listing/query.rpc.Query"; +import * as _170 from "./perpetuals/query.rpc.Query"; +import * as _171 from "./prices/query.rpc.Query"; +import * as _172 from "./ratelimit/query.rpc.Query"; +import * as _173 from "./revshare/query.rpc.Query"; +import * as _174 from "./rewards/query.rpc.Query"; +import * as _175 from "./sending/query.rpc.Query"; +import * as _176 from "./stats/query.rpc.Query"; +import * as _177 from "./subaccounts/query.rpc.Query"; +import * as _178 from "./vault/query.rpc.Query"; +import * as _179 from "./vest/query.rpc.Query"; +import * as _180 from "./accountplus/tx.rpc.msg"; +import * as _181 from "./affiliates/tx.rpc.msg"; +import * as _182 from "./blocktime/tx.rpc.msg"; +import * as _183 from "./bridge/tx.rpc.msg"; +import * as _184 from "./clob/tx.rpc.msg"; +import * as _185 from "./delaymsg/tx.rpc.msg"; +import * as _186 from "./feetiers/tx.rpc.msg"; +import * as _187 from "./govplus/tx.rpc.msg"; +import * as _188 from "./listing/tx.rpc.msg"; +import * as _189 from "./perpetuals/tx.rpc.msg"; +import * as _190 from "./prices/tx.rpc.msg"; +import * as _191 from "./ratelimit/tx.rpc.msg"; +import * as _192 from "./revshare/tx.rpc.msg"; +import * as _193 from "./rewards/tx.rpc.msg"; +import * as _194 from "./sending/tx.rpc.msg"; +import * as _195 from "./stats/tx.rpc.msg"; +import * as _196 from "./vault/tx.rpc.msg"; +import * as _197 from "./vest/tx.rpc.msg"; +import * as _198 from "./lcd"; +import * as _199 from "./rpc.query"; +import * as _200 from "./rpc.tx"; export namespace dydxprotocol { export const accountplus = { ..._5, ..._6, @@ -193,33 +194,33 @@ export namespace dydxprotocol { ..._8, ..._9, ..._10, - ..._139, - ..._158, - ..._179 + ..._140, + ..._159, + ..._180 }; export const affiliates = { ..._11, ..._12, ..._13, ..._14, - ..._140, - ..._159, - ..._180 + ..._141, + ..._160, + ..._181 }; export const assets = { ..._15, ..._16, ..._17, ..._18, - ..._141, - ..._160 + ..._142, + ..._161 }; export const blocktime = { ..._19, ..._20, ..._21, ..._22, ..._23, - ..._142, - ..._161, - ..._181 + ..._143, + ..._162, + ..._182 }; export const bridge = { ..._24, ..._25, @@ -227,9 +228,9 @@ export namespace dydxprotocol { ..._27, ..._28, ..._29, - ..._143, - ..._162, - ..._182 + ..._144, + ..._163, + ..._183 }; export const clob = { ..._30, ..._31, @@ -247,9 +248,9 @@ export namespace dydxprotocol { ..._43, ..._44, ..._45, - ..._144, - ..._163, - ..._183 + ..._145, + ..._164, + ..._184 }; export namespace daemons { export const bridge = { ..._46 @@ -264,15 +265,15 @@ export namespace dydxprotocol { ..._51, ..._52, ..._53, - ..._145, - ..._164, - ..._184 + ..._146, + ..._165, + ..._185 }; export const epochs = { ..._54, ..._55, ..._56, - ..._146, - ..._165 + ..._147, + ..._166 }; export const feetiers = { ..._57, ..._58, @@ -280,15 +281,15 @@ export namespace dydxprotocol { ..._60, ..._61, ..._62, - ..._147, - ..._166, - ..._185 + ..._148, + ..._167, + ..._186 }; export const govplus = { ..._63, ..._64, ..._65, - ..._167, - ..._186 + ..._168, + ..._187 }; export namespace indexer { export const events = { ..._66 @@ -315,18 +316,18 @@ export namespace dydxprotocol { ..._77, ..._78, ..._79, - ..._148, - ..._168, - ..._187 + ..._149, + ..._169, + ..._188 }; export const perpetuals = { ..._80, ..._81, ..._82, ..._83, ..._84, - ..._149, - ..._169, - ..._188 + ..._150, + ..._170, + ..._189 }; export const prices = { ..._85, ..._86, @@ -334,9 +335,9 @@ export namespace dydxprotocol { ..._88, ..._89, ..._90, - ..._150, - ..._170, - ..._189 + ..._151, + ..._171, + ..._190 }; export const ratelimit = { ..._91, ..._92, @@ -344,43 +345,43 @@ export namespace dydxprotocol { ..._94, ..._95, ..._96, - ..._151, - ..._171, - ..._190 + ..._152, + ..._172, + ..._191 }; export const revshare = { ..._97, ..._98, ..._99, ..._100, ..._101, - ..._152, - ..._172, - ..._191 + ..._153, + ..._173, + ..._192 }; export const rewards = { ..._102, ..._103, ..._104, ..._105, ..._106, - ..._153, - ..._173, - ..._192 + ..._154, + ..._174, + ..._193 }; export const sending = { ..._107, ..._108, ..._109, ..._110, - ..._174, - ..._193 + ..._175, + ..._194 }; export const stats = { ..._111, ..._112, ..._113, ..._114, ..._115, - ..._154, - ..._175, - ..._194 + ..._155, + ..._176, + ..._195 }; export const subaccounts = { ..._116, ..._117, @@ -388,29 +389,30 @@ export namespace dydxprotocol { ..._119, ..._120, ..._121, - ..._155, - ..._176 + ..._122, + ..._156, + ..._177 }; - export const vault = { ..._122, - ..._123, + export const vault = { ..._123, ..._124, ..._125, ..._126, ..._127, - ..._156, - ..._177, - ..._195 - }; - export const vest = { ..._128, - ..._129, - ..._130, - ..._131, + ..._128, ..._157, ..._178, ..._196 }; - export const ClientFactory = { ..._197, - ..._198, - ..._199 + export const vest = { ..._129, + ..._130, + ..._131, + ..._132, + ..._158, + ..._179, + ..._197 + }; + export const ClientFactory = { ..._198, + ..._199, + ..._200 }; } \ No newline at end of file diff --git a/indexer/packages/v4-protos/src/codegen/dydxprotocol/clob/query.ts b/indexer/packages/v4-protos/src/codegen/dydxprotocol/clob/query.ts index 4039028cef..8163ff0c9c 100644 --- a/indexer/packages/v4-protos/src/codegen/dydxprotocol/clob/query.ts +++ b/indexer/packages/v4-protos/src/codegen/dydxprotocol/clob/query.ts @@ -299,18 +299,18 @@ export interface QueryLeverageResponseSDKType { export interface ClobPairLeverageInfo { /** The clob pair ID. */ clobPairId: number; - /** The leverage amount. */ + /** The user selected imf. */ - leverage: number; + customImfPpm: number; } /** ClobPairLeverageInfo represents the leverage setting for a single clob pair. */ export interface ClobPairLeverageInfoSDKType { /** The clob pair ID. */ clob_pair_id: number; - /** The leverage amount. */ + /** The user selected imf. */ - leverage: number; + custom_imf_ppm: number; } /** * StreamOrderbookUpdatesRequest is a request message for the @@ -1459,7 +1459,7 @@ export const QueryLeverageResponse = { function createBaseClobPairLeverageInfo(): ClobPairLeverageInfo { return { clobPairId: 0, - leverage: 0 + customImfPpm: 0 }; } @@ -1469,8 +1469,8 @@ export const ClobPairLeverageInfo = { writer.uint32(8).uint32(message.clobPairId); } - if (message.leverage !== 0) { - writer.uint32(16).uint32(message.leverage); + if (message.customImfPpm !== 0) { + writer.uint32(16).uint32(message.customImfPpm); } return writer; @@ -1490,7 +1490,7 @@ export const ClobPairLeverageInfo = { break; case 2: - message.leverage = reader.uint32(); + message.customImfPpm = reader.uint32(); break; default: @@ -1505,7 +1505,7 @@ export const ClobPairLeverageInfo = { fromPartial(object: DeepPartial): ClobPairLeverageInfo { const message = createBaseClobPairLeverageInfo(); message.clobPairId = object.clobPairId ?? 0; - message.leverage = object.leverage ?? 0; + message.customImfPpm = object.customImfPpm ?? 0; return message; } diff --git a/indexer/packages/v4-protos/src/codegen/dydxprotocol/clob/tx.ts b/indexer/packages/v4-protos/src/codegen/dydxprotocol/clob/tx.ts index f78404a729..85f2ebc96e 100644 --- a/indexer/packages/v4-protos/src/codegen/dydxprotocol/clob/tx.ts +++ b/indexer/packages/v4-protos/src/codegen/dydxprotocol/clob/tx.ts @@ -387,18 +387,18 @@ export interface MsgUpdateLiquidationsConfigResponseSDKType {} export interface LeverageEntry { /** The clob pair ID. */ clobPairId: number; - /** The leverage amount. */ + /** The user selected imf. */ - leverage: number; + customImfPpm: number; } /** LeverageEntry represents a single clob pair leverage setting. */ export interface LeverageEntrySDKType { /** The clob pair ID. */ clob_pair_id: number; - /** The leverage amount. */ + /** The user selected imf. */ - leverage: number; + custom_imf_ppm: number; } /** * MsgUpdateLeverage is a request type used for updating leverage for @@ -1388,7 +1388,7 @@ export const MsgUpdateLiquidationsConfigResponse = { function createBaseLeverageEntry(): LeverageEntry { return { clobPairId: 0, - leverage: 0 + customImfPpm: 0 }; } @@ -1398,8 +1398,8 @@ export const LeverageEntry = { writer.uint32(8).uint32(message.clobPairId); } - if (message.leverage !== 0) { - writer.uint32(16).uint32(message.leverage); + if (message.customImfPpm !== 0) { + writer.uint32(16).uint32(message.customImfPpm); } return writer; @@ -1419,7 +1419,7 @@ export const LeverageEntry = { break; case 2: - message.leverage = reader.uint32(); + message.customImfPpm = reader.uint32(); break; default: @@ -1434,7 +1434,7 @@ export const LeverageEntry = { fromPartial(object: DeepPartial): LeverageEntry { const message = createBaseLeverageEntry(); message.clobPairId = object.clobPairId ?? 0; - message.leverage = object.leverage ?? 0; + message.customImfPpm = object.customImfPpm ?? 0; return message; } diff --git a/indexer/packages/v4-protos/src/codegen/dydxprotocol/subaccounts/leverage.ts b/indexer/packages/v4-protos/src/codegen/dydxprotocol/subaccounts/leverage.ts new file mode 100644 index 0000000000..ff6ad67408 --- /dev/null +++ b/indexer/packages/v4-protos/src/codegen/dydxprotocol/subaccounts/leverage.ts @@ -0,0 +1,138 @@ +import * as _m0 from "protobufjs/minimal"; +import { DeepPartial } from "../../helpers"; +/** + * PerpetualLeverageEntry represents a single perpetual leverage setting for + * internal storage + */ + +export interface PerpetualLeverageEntry { + /** The perpetual ID (internal storage format) */ + perpetualId: number; + /** The user selected IMF in parts per million */ + + customImfPpm: number; +} +/** + * PerpetualLeverageEntry represents a single perpetual leverage setting for + * internal storage + */ + +export interface PerpetualLeverageEntrySDKType { + /** The perpetual ID (internal storage format) */ + perpetual_id: number; + /** The user selected IMF in parts per million */ + + custom_imf_ppm: number; +} +/** LeverageData represents the leverage settings for a subaccount */ + +export interface LeverageData { + /** List of leverage entries for this subaccount */ + entries: PerpetualLeverageEntry[]; +} +/** LeverageData represents the leverage settings for a subaccount */ + +export interface LeverageDataSDKType { + /** List of leverage entries for this subaccount */ + entries: PerpetualLeverageEntrySDKType[]; +} + +function createBasePerpetualLeverageEntry(): PerpetualLeverageEntry { + return { + perpetualId: 0, + customImfPpm: 0 + }; +} + +export const PerpetualLeverageEntry = { + encode(message: PerpetualLeverageEntry, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.perpetualId !== 0) { + writer.uint32(8).uint32(message.perpetualId); + } + + if (message.customImfPpm !== 0) { + writer.uint32(16).uint32(message.customImfPpm); + } + + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): PerpetualLeverageEntry { + const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBasePerpetualLeverageEntry(); + + while (reader.pos < end) { + const tag = reader.uint32(); + + switch (tag >>> 3) { + case 1: + message.perpetualId = reader.uint32(); + break; + + case 2: + message.customImfPpm = reader.uint32(); + break; + + default: + reader.skipType(tag & 7); + break; + } + } + + return message; + }, + + fromPartial(object: DeepPartial): PerpetualLeverageEntry { + const message = createBasePerpetualLeverageEntry(); + message.perpetualId = object.perpetualId ?? 0; + message.customImfPpm = object.customImfPpm ?? 0; + return message; + } + +}; + +function createBaseLeverageData(): LeverageData { + return { + entries: [] + }; +} + +export const LeverageData = { + encode(message: LeverageData, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + for (const v of message.entries) { + PerpetualLeverageEntry.encode(v!, writer.uint32(10).fork()).ldelim(); + } + + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): LeverageData { + const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseLeverageData(); + + while (reader.pos < end) { + const tag = reader.uint32(); + + switch (tag >>> 3) { + case 1: + message.entries.push(PerpetualLeverageEntry.decode(reader, reader.uint32())); + break; + + default: + reader.skipType(tag & 7); + break; + } + } + + return message; + }, + + fromPartial(object: DeepPartial): LeverageData { + const message = createBaseLeverageData(); + message.entries = object.entries?.map(e => PerpetualLeverageEntry.fromPartial(e)) || []; + return message; + } + +}; \ No newline at end of file diff --git a/indexer/packages/v4-protos/src/codegen/gogoproto/bundle.ts b/indexer/packages/v4-protos/src/codegen/gogoproto/bundle.ts index dbcb66d660..c96e8e29e0 100644 --- a/indexer/packages/v4-protos/src/codegen/gogoproto/bundle.ts +++ b/indexer/packages/v4-protos/src/codegen/gogoproto/bundle.ts @@ -1,3 +1,3 @@ -import * as _132 from "./gogo"; -export const gogoproto = { ..._132 +import * as _133 from "./gogo"; +export const gogoproto = { ..._133 }; \ No newline at end of file diff --git a/indexer/packages/v4-protos/src/codegen/google/bundle.ts b/indexer/packages/v4-protos/src/codegen/google/bundle.ts index b4251166ce..859b1b0306 100644 --- a/indexer/packages/v4-protos/src/codegen/google/bundle.ts +++ b/indexer/packages/v4-protos/src/codegen/google/bundle.ts @@ -1,16 +1,16 @@ -import * as _133 from "./api/annotations"; -import * as _134 from "./api/http"; -import * as _135 from "./protobuf/descriptor"; -import * as _136 from "./protobuf/duration"; -import * as _137 from "./protobuf/timestamp"; -import * as _138 from "./protobuf/any"; +import * as _134 from "./api/annotations"; +import * as _135 from "./api/http"; +import * as _136 from "./protobuf/descriptor"; +import * as _137 from "./protobuf/duration"; +import * as _138 from "./protobuf/timestamp"; +import * as _139 from "./protobuf/any"; export namespace google { - export const api = { ..._133, - ..._134 + export const api = { ..._134, + ..._135 }; - export const protobuf = { ..._135, - ..._136, + export const protobuf = { ..._136, ..._137, - ..._138 + ..._138, + ..._139 }; } \ No newline at end of file diff --git a/proto/dydxprotocol/clob/query.proto b/proto/dydxprotocol/clob/query.proto index 06cf3d02ac..93d1ae5fc2 100644 --- a/proto/dydxprotocol/clob/query.proto +++ b/proto/dydxprotocol/clob/query.proto @@ -199,8 +199,8 @@ message QueryLeverageResponse { message ClobPairLeverageInfo { // The clob pair ID. uint32 clob_pair_id = 1; - // The leverage amount. - uint32 leverage = 2; + // The user selected imf. + uint32 custom_imf_ppm = 2; } // StreamOrderbookUpdatesRequest is a request message for the diff --git a/proto/dydxprotocol/clob/tx.proto b/proto/dydxprotocol/clob/tx.proto index c5736b04a0..1f742f4dbd 100644 --- a/proto/dydxprotocol/clob/tx.proto +++ b/proto/dydxprotocol/clob/tx.proto @@ -219,8 +219,8 @@ message MsgUpdateLiquidationsConfigResponse {} message LeverageEntry { // The clob pair ID. uint32 clob_pair_id = 1; - // The leverage amount. - uint32 leverage = 2; + // The user selected imf. + uint32 custom_imf_ppm = 2; } // MsgUpdateLeverage is a request type used for updating leverage for diff --git a/proto/dydxprotocol/subaccounts/leverage.proto b/proto/dydxprotocol/subaccounts/leverage.proto new file mode 100644 index 0000000000..a27b0f7bd8 --- /dev/null +++ b/proto/dydxprotocol/subaccounts/leverage.proto @@ -0,0 +1,19 @@ +syntax = "proto3"; +package dydxprotocol.subaccounts; + +option go_package = "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types"; + +// PerpetualLeverageEntry represents a single perpetual leverage setting for +// internal storage +message PerpetualLeverageEntry { + // The perpetual ID (internal storage format) + uint32 perpetual_id = 1; + // The user selected IMF in parts per million + uint32 custom_imf_ppm = 2; +} + +// LeverageData represents the leverage settings for a subaccount +message LeverageData { + // List of leverage entries for this subaccount + repeated PerpetualLeverageEntry entries = 1; +} diff --git a/protocol/daemons/liquidation/client/sub_task_runner.go b/protocol/daemons/liquidation/client/sub_task_runner.go index f9f2e77675..bcee093424 100644 --- a/protocol/daemons/liquidation/client/sub_task_runner.go +++ b/protocol/daemons/liquidation/client/sub_task_runner.go @@ -341,6 +341,7 @@ func (c *Client) CheckSubaccountCollateralization( risk, err := salib.GetRiskForSubaccount( settledSubaccount, perpInfos, + nil, // No leverage needed for liquidation calculations ) return risk.IsLiquidatable(), risk.NC.Sign() < 0, nil diff --git a/protocol/mocks/ClobKeeper.go b/protocol/mocks/ClobKeeper.go index ab6d08521d..9bb590daf7 100644 --- a/protocol/mocks/ClobKeeper.go +++ b/protocol/mocks/ClobKeeper.go @@ -5,10 +5,12 @@ package mocks import ( big "math/big" - indexer_manager "github.com/dydxprotocol/v4-chain/protocol/indexer/indexer_manager" - affiliatetypes "github.com/dydxprotocol/v4-chain/protocol/x/affiliates/types" + affiliatestypes "github.com/dydxprotocol/v4-chain/protocol/x/affiliates/types" + clobtypes "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" + indexer_manager "github.com/dydxprotocol/v4-chain/protocol/indexer/indexer_manager" + log "cosmossdk.io/log" mock "github.com/stretchr/testify/mock" @@ -478,34 +480,6 @@ func (_m *ClobKeeper) GetMaxAndMinPositionNotionalLiquidatable(ctx types.Context return r0, r1, r2 } -// GetMaxLeverageForPerpetual provides a mock function with given fields: ctx, perpetualId -func (_m *ClobKeeper) GetMaxLeverageForPerpetual(ctx types.Context, perpetualId uint32) (uint32, error) { - ret := _m.Called(ctx, perpetualId) - - if len(ret) == 0 { - panic("no return value specified for GetMaxLeverageForPerpetual") - } - - var r0 uint32 - var r1 error - if rf, ok := ret.Get(0).(func(types.Context, uint32) (uint32, error)); ok { - return rf(ctx, perpetualId) - } - if rf, ok := ret.Get(0).(func(types.Context, uint32) uint32); ok { - r0 = rf(ctx, perpetualId) - } else { - r0 = ret.Get(0).(uint32) - } - - if rf, ok := ret.Get(1).(func(types.Context, uint32) error); ok { - r1 = rf(ctx, perpetualId) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - // GetPerpetualPositionToLiquidate provides a mock function with given fields: ctx, subaccountId func (_m *ClobKeeper) GetPerpetualPositionToLiquidate(ctx types.Context, subaccountId subaccountstypes.SubaccountId) (uint32, error) { ret := _m.Called(ctx, subaccountId) @@ -650,6 +624,26 @@ func (_m *ClobKeeper) GetSubaccountMaxNotionalLiquidatable(ctx types.Context, su return r0, r1 } +// GetSubaccountsKeeper provides a mock function with no fields +func (_m *ClobKeeper) GetSubaccountsKeeper() clobtypes.SubaccountsKeeper { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetSubaccountsKeeper") + } + + var r0 clobtypes.SubaccountsKeeper + if rf, ok := ret.Get(0).(func() clobtypes.SubaccountsKeeper); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(clobtypes.SubaccountsKeeper) + } + } + + return r0 +} + // HandleMsgCancelOrder provides a mock function with given fields: ctx, msg func (_m *ClobKeeper) HandleMsgCancelOrder(ctx types.Context, msg *clobtypes.MsgCancelOrder) error { ret := _m.Called(ctx, msg) @@ -1038,8 +1032,8 @@ func (_m *ClobKeeper) ProcessProposerOperations(ctx types.Context, operations [] return r0 } -// ProcessSingleMatch provides a mock function with given fields: ctx, matchWithOrders, affiliatesWhitelistMap -func (_m *ClobKeeper) ProcessSingleMatch(ctx types.Context, matchWithOrders *clobtypes.MatchWithOrders, affiliateOverrides map[string]bool, affiliateParameters affiliatetypes.AffiliateParameters) (bool, subaccountstypes.UpdateResult, subaccountstypes.UpdateResult, *big.Int, error) { +// ProcessSingleMatch provides a mock function with given fields: ctx, matchWithOrders, affiliateOverrides, affiliateParameters +func (_m *ClobKeeper) ProcessSingleMatch(ctx types.Context, matchWithOrders *clobtypes.MatchWithOrders, affiliateOverrides map[string]bool, affiliateParameters affiliatestypes.AffiliateParameters) (bool, subaccountstypes.UpdateResult, subaccountstypes.UpdateResult, *big.Int, error) { ret := _m.Called(ctx, matchWithOrders, affiliateOverrides, affiliateParameters) if len(ret) == 0 { @@ -1051,28 +1045,28 @@ func (_m *ClobKeeper) ProcessSingleMatch(ctx types.Context, matchWithOrders *clo var r2 subaccountstypes.UpdateResult var r3 *big.Int var r4 error - if rf, ok := ret.Get(0).(func(types.Context, *clobtypes.MatchWithOrders, map[string]bool, affiliatetypes.AffiliateParameters) (bool, subaccountstypes.UpdateResult, subaccountstypes.UpdateResult, *big.Int, error)); ok { + if rf, ok := ret.Get(0).(func(types.Context, *clobtypes.MatchWithOrders, map[string]bool, affiliatestypes.AffiliateParameters) (bool, subaccountstypes.UpdateResult, subaccountstypes.UpdateResult, *big.Int, error)); ok { return rf(ctx, matchWithOrders, affiliateOverrides, affiliateParameters) } - if rf, ok := ret.Get(0).(func(types.Context, *clobtypes.MatchWithOrders, map[string]bool, affiliatetypes.AffiliateParameters) bool); ok { + if rf, ok := ret.Get(0).(func(types.Context, *clobtypes.MatchWithOrders, map[string]bool, affiliatestypes.AffiliateParameters) bool); ok { r0 = rf(ctx, matchWithOrders, affiliateOverrides, affiliateParameters) } else { r0 = ret.Get(0).(bool) } - if rf, ok := ret.Get(1).(func(types.Context, *clobtypes.MatchWithOrders, map[string]bool, affiliatetypes.AffiliateParameters) subaccountstypes.UpdateResult); ok { + if rf, ok := ret.Get(1).(func(types.Context, *clobtypes.MatchWithOrders, map[string]bool, affiliatestypes.AffiliateParameters) subaccountstypes.UpdateResult); ok { r1 = rf(ctx, matchWithOrders, affiliateOverrides, affiliateParameters) } else { r1 = ret.Get(1).(subaccountstypes.UpdateResult) } - if rf, ok := ret.Get(2).(func(types.Context, *clobtypes.MatchWithOrders, map[string]bool, affiliatetypes.AffiliateParameters) subaccountstypes.UpdateResult); ok { + if rf, ok := ret.Get(2).(func(types.Context, *clobtypes.MatchWithOrders, map[string]bool, affiliatestypes.AffiliateParameters) subaccountstypes.UpdateResult); ok { r2 = rf(ctx, matchWithOrders, affiliateOverrides, affiliateParameters) } else { r2 = ret.Get(2).(subaccountstypes.UpdateResult) } - if rf, ok := ret.Get(3).(func(types.Context, *clobtypes.MatchWithOrders, map[string]bool, affiliatetypes.AffiliateParameters) *big.Int); ok { + if rf, ok := ret.Get(3).(func(types.Context, *clobtypes.MatchWithOrders, map[string]bool, affiliatestypes.AffiliateParameters) *big.Int); ok { r3 = rf(ctx, matchWithOrders, affiliateOverrides, affiliateParameters) } else { if ret.Get(3) != nil { @@ -1080,7 +1074,7 @@ func (_m *ClobKeeper) ProcessSingleMatch(ctx types.Context, matchWithOrders *clo } } - if rf, ok := ret.Get(4).(func(types.Context, *clobtypes.MatchWithOrders, map[string]bool, affiliatetypes.AffiliateParameters) error); ok { + if rf, ok := ret.Get(4).(func(types.Context, *clobtypes.MatchWithOrders, map[string]bool, affiliatestypes.AffiliateParameters) error); ok { r4 = rf(ctx, matchWithOrders, affiliateOverrides, affiliateParameters) } else { r4 = ret.Error(4) diff --git a/protocol/testutil/app/app.go b/protocol/testutil/app/app.go index 6d3dd3d0fe..246d96955e 100644 --- a/protocol/testutil/app/app.go +++ b/protocol/testutil/app/app.go @@ -1349,7 +1349,11 @@ func launchValidatorInDir( // MustMakeCheckTxsWithClobMsg creates one signed RequestCheckTx for each msg passed in. // The messsage must use one of the hard-coded well known subaccount owners otherwise this will panic. -func MustMakeCheckTxsWithClobMsg[T clobtypes.MsgPlaceOrder | clobtypes.MsgCancelOrder | clobtypes.MsgBatchCancel]( +func MustMakeCheckTxsWithClobMsg[ + T clobtypes.MsgPlaceOrder | + clobtypes.MsgCancelOrder | + clobtypes.MsgBatchCancel | + clobtypes.MsgUpdateLeverage]( ctx sdk.Context, app *app.App, messages ...T, @@ -1368,6 +1372,9 @@ func MustMakeCheckTxsWithClobMsg[T clobtypes.MsgPlaceOrder | clobtypes.MsgCancel case clobtypes.MsgBatchCancel: signerAddress = v.SubaccountId.Owner m = &v + case clobtypes.MsgUpdateLeverage: + signerAddress = v.SubaccountId.Owner + m = &v default: panic(fmt.Errorf("MustMakeCheckTxsWithClobMsg: Unknown message type %T", msg)) } diff --git a/protocol/testutil/keeper/listing.go b/protocol/testutil/keeper/listing.go index 5bbdf3abdd..4d33ec5560 100644 --- a/protocol/testutil/keeper/listing.go +++ b/protocol/testutil/keeper/listing.go @@ -141,6 +141,7 @@ func ListingKeepers( db, cdc, ) + // Create subaccounts keeper first with nil leverageKeeper subaccountsKeeper, _ = createSubaccountsKeeper( stateStore, db, @@ -172,6 +173,7 @@ func ListingKeepers( mockIndexerEventManager, transientStoreKey, ) + // Create the listing keeper keeper, storeKey, _ = createListingKeeper( stateStore, diff --git a/protocol/x/clob/ante/clob.go b/protocol/x/clob/ante/clob.go index 442f7729ab..ea982c8f59 100644 --- a/protocol/x/clob/ante/clob.go +++ b/protocol/x/clob/ante/clob.go @@ -193,14 +193,19 @@ func (cd ClobDecorator) AnteHandle( return ctx, err } case *types.MsgUpdateLeverage: - // Process UpdateLeverage message - just store the leverage data + // Process UpdateLeverage message - delegate to subaccounts keeper // Convert from LeverageEntry slice to map perpetualLeverageMap, err := types.ValidateAndConstructPerpetualLeverageMap(ctx, msg, cd.clobKeeper) if err != nil { return ctx, err } - if err := cd.clobKeeper.UpdateLeverage(ctx, msg.SubaccountId, perpetualLeverageMap); err != nil { + // Delegate to subaccounts keeper for leverage storage and validation + if err := cd.clobKeeper.GetSubaccountsKeeper().UpdateLeverage( + ctx, + msg.SubaccountId, + perpetualLeverageMap, + ); err != nil { log.DebugLog( ctx, "Failed to update leverage in ante handler", diff --git a/protocol/x/clob/client/cli/tx_update_leverage.go b/protocol/x/clob/client/cli/tx_update_leverage.go index b87c4e2a98..e2063281b4 100644 --- a/protocol/x/clob/client/cli/tx_update_leverage.go +++ b/protocol/x/clob/client/cli/tx_update_leverage.go @@ -3,6 +3,7 @@ package cli import ( "encoding/json" "fmt" + "sort" "strconv" "github.com/spf13/cobra" @@ -38,16 +39,23 @@ func CmdUpdateLeverage() *cobra.Command { return fmt.Errorf("invalid leverage map JSON: %w", err) } - // Convert string keys to uint32 and create LeverageEntry slice + // Sort the keys to ensure deterministic ordering + keys := make([]string, 0, len(leverageMap)) + for clobPairIdStr := range leverageMap { + keys = append(keys, clobPairIdStr) + } + sort.Strings(keys) + var clobPairLeverage []*types.LeverageEntry - for clobPairIdStr, leverage := range leverageMap { + for _, clobPairIdStr := range keys { clobPairId, err := strconv.ParseUint(clobPairIdStr, 10, 32) if err != nil { return fmt.Errorf("invalid clob pair ID %s: %w", clobPairIdStr, err) } + clobPairLeverage = append(clobPairLeverage, &types.LeverageEntry{ - ClobPairId: uint32(clobPairId), - Leverage: leverage, + ClobPairId: uint32(clobPairId), + CustomImfPpm: leverageMap[clobPairIdStr], }) } diff --git a/protocol/x/clob/e2e/app_test.go b/protocol/x/clob/e2e/app_test.go index 20bacc5efa..0427a9c233 100644 --- a/protocol/x/clob/e2e/app_test.go +++ b/protocol/x/clob/e2e/app_test.go @@ -321,8 +321,8 @@ var ( SubaccountId: &constants.Alice_Num0, ClobPairLeverage: []*clobtypes.LeverageEntry{ { - ClobPairId: 0, - Leverage: 5, + ClobPairId: 0, + CustomImfPpm: 200_000, }, }, } @@ -330,17 +330,17 @@ var ( SubaccountId: &constants.Alice_Num0, ClobPairLeverage: []*clobtypes.LeverageEntry{ { - ClobPairId: 1, - Leverage: 10, + ClobPairId: 1, + CustomImfPpm: 100_000, }, }, } - UpdateLeverage_Alice_Num1_PerpId0_Lev3 = clobtypes.MsgUpdateLeverage{ + UpdateLeverage_Alice_Num1_PerpId0_Lev4 = clobtypes.MsgUpdateLeverage{ SubaccountId: &constants.Alice_Num1, ClobPairLeverage: []*clobtypes.LeverageEntry{ { - ClobPairId: 0, - Leverage: 3, + ClobPairId: 0, + CustomImfPpm: 250_000, }, }, } @@ -348,8 +348,8 @@ var ( SubaccountId: &constants.Bob_Num0, ClobPairLeverage: []*clobtypes.LeverageEntry{ { - ClobPairId: 0, - Leverage: 5, + ClobPairId: 0, + CustomImfPpm: 200_000, }, }, } diff --git a/protocol/x/clob/keeper/grpc_query_leverage.go b/protocol/x/clob/keeper/grpc_query_leverage.go index 9ffe2ab413..ac6800a254 100644 --- a/protocol/x/clob/keeper/grpc_query_leverage.go +++ b/protocol/x/clob/keeper/grpc_query_leverage.go @@ -2,7 +2,9 @@ package keeper import ( "context" + "sort" + errorsmod "cosmossdk.io/errors" "github.com/dydxprotocol/v4-chain/protocol/lib" "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" @@ -22,23 +24,33 @@ func (k Keeper) Leverage( ctx := lib.UnwrapSDKContext(c, types.ModuleName) // Get leverage for the subaccount - leverage, exists := k.GetLeverage(ctx, &satypes.SubaccountId{ + leverageMap, exists := k.subaccountsKeeper.GetLeverage(ctx, &satypes.SubaccountId{ Owner: req.Owner, Number: req.Number, }) if !exists { - leverage = make(map[uint32]uint32) + leverageMap = make(map[uint32]uint32) } - clobPairLeverage := make([]*types.ClobPairLeverageInfo, 0, len(leverage)) - for clobPairId, leverage := range leverage { + // Sort the keys to ensure deterministic ordering + keys := make([]uint32, 0, len(leverageMap)) + for perpetualId := range leverageMap { + keys = append(keys, perpetualId) + } + sort.Slice(keys, func(i, j int) bool { + return keys[i] < keys[j] + }) + + clobPairLeverage := make([]*types.ClobPairLeverageInfo, 0, len(leverageMap)) + for _, perpetualId := range keys { + clobPairId, err := k.GetClobPairIdForPerpetual(ctx, perpetualId) + if err != nil { + return nil, status.Error(codes.Internal, errorsmod.Wrap(err, "failed to get clob pair id for perpetual").Error()) + } clobPairLeverage = append(clobPairLeverage, &types.ClobPairLeverageInfo{ - ClobPairId: clobPairId, - Leverage: leverage, + ClobPairId: clobPairId.ToUint32(), + CustomImfPpm: leverageMap[perpetualId], }) } - - return &types.QueryLeverageResponse{ - ClobPairLeverage: clobPairLeverage, - }, nil + return &types.QueryLeverageResponse{ClobPairLeverage: clobPairLeverage}, nil } diff --git a/protocol/x/clob/keeper/keeper.go b/protocol/x/clob/keeper/keeper.go index 4847e09658..ac5e1a7db6 100644 --- a/protocol/x/clob/keeper/keeper.go +++ b/protocol/x/clob/keeper/keeper.go @@ -164,6 +164,10 @@ func (k Keeper) GetFullNodeStreamingManager() streamingtypes.FullNodeStreamingMa return k.streamingManager } +func (k Keeper) GetSubaccountsKeeper() types.SubaccountsKeeper { + return k.subaccountsKeeper +} + func (k Keeper) GetCrossInsuranceFundBalance(ctx sdk.Context) *big.Int { return k.subaccountsKeeper.GetCrossInsuranceFundBalance(ctx) } diff --git a/protocol/x/clob/keeper/leverage.go b/protocol/x/clob/keeper/leverage.go index 069c3a5fd1..ce7ae24b10 100644 --- a/protocol/x/clob/keeper/leverage.go +++ b/protocol/x/clob/keeper/leverage.go @@ -1,117 +1,15 @@ package keeper import ( - "encoding/json" - - errorsmod "cosmossdk.io/errors" - "cosmossdk.io/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/dydxprotocol/v4-chain/protocol/lib" - "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" ) -// getLeverageStore returns a prefix store where leverage data is stored. -func (k Keeper) getLeverageStore(ctx sdk.Context) prefix.Store { - return prefix.NewStore(ctx.KVStore(k.storeKey), []byte(types.LeverageKeyPrefix)) -} - -// leverageKey returns the store key to retrieve leverage data for a subaccount. -func leverageKey(subaccountId *satypes.SubaccountId) []byte { - return subaccountId.ToStateKey() -} - -// SetLeverage stores leverage data for a subaccount. -func (k Keeper) SetLeverage(ctx sdk.Context, subaccountId *satypes.SubaccountId, leverageMap map[uint32]uint32) { - store := k.getLeverageStore(ctx) - key := leverageKey(subaccountId) - - // Marshal and store the map using JSON - b, err := json.Marshal(leverageMap) - if err != nil { - panic(err) - } - store.Set(key, b) -} - -// GetLeverage retrieves leverage data for a subaccount. -func (k Keeper) GetLeverage(ctx sdk.Context, subaccountId *satypes.SubaccountId) (map[uint32]uint32, bool) { - store := k.getLeverageStore(ctx) - key := leverageKey(subaccountId) - - b := store.Get(key) - if b == nil { - return nil, false - } - - var leverageMap map[uint32]uint32 - if err := json.Unmarshal(b, &leverageMap); err != nil { - panic(err) - } - - return leverageMap, true -} - // UpdateLeverage updates leverage for specific perpetuals for a subaccount. func (k Keeper) UpdateLeverage( ctx sdk.Context, subaccountId *satypes.SubaccountId, perpetualLeverage map[uint32]uint32, ) error { - // Validate leverage against maximum allowed for each perpetual - for perpetualId, leverage := range perpetualLeverage { - maxLeverage, err := k.GetMaxLeverageForPerpetual(ctx, perpetualId) - if err != nil { - return errorsmod.Wrapf( - types.ErrInvalidLeverage, - "failed to get max leverage for perpetual %d: %v", - perpetualId, - err, - ) - } - - if leverage > maxLeverage { - return errorsmod.Wrapf( - types.ErrLeverageExceedsMaximum, - "leverage %d exceeds maximum allowed %d for perpetual %d", - leverage, - maxLeverage, - perpetualId, - ) - } - } - - // Get existing leverage data - existingLeverage, exists := k.GetLeverage(ctx, subaccountId) - if !exists { - existingLeverage = make(map[uint32]uint32) - } - - // Update with new leverage values - for perpetualId, leverage := range perpetualLeverage { - existingLeverage[perpetualId] = leverage - } - - // Store updated leverage - k.SetLeverage(ctx, subaccountId, existingLeverage) - return nil -} - -// GetMaxLeverageForPerpetual calculates the maximum leverage allowed for a perpetual -// based on its liquidity tier's initial margin requirement. -// Max leverage = 1,000,000 / initial_margin_ppm -func (k Keeper) GetMaxLeverageForPerpetual(ctx sdk.Context, perpetualId uint32) (uint32, error) { - // Get the perpetual and its liquidity tier in one call - _, _, liquidityTier, err := k.perpetualsKeeper.GetPerpetualAndMarketPriceAndLiquidityTier(ctx, perpetualId) - if err != nil { - return 0, err - } - - // Calculate max leverage: 1,000,000 / initial_margin_ppm - if liquidityTier.InitialMarginPpm == 0 { - return 0, types.ErrInitialMarginPpmIsZero - } - - maxLeverage := lib.OneMillion / liquidityTier.InitialMarginPpm - return maxLeverage, nil + return k.subaccountsKeeper.UpdateLeverage(ctx, subaccountId, perpetualLeverage) } diff --git a/protocol/x/clob/keeper/leverage_e2e_test.go b/protocol/x/clob/keeper/leverage_e2e_test.go new file mode 100644 index 0000000000..96698ce79d --- /dev/null +++ b/protocol/x/clob/keeper/leverage_e2e_test.go @@ -0,0 +1,266 @@ +package keeper_test + +import ( + "math/big" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/dydxprotocol/v4-chain/protocol/dtypes" + testapp "github.com/dydxprotocol/v4-chain/protocol/testutil/app" + "github.com/dydxprotocol/v4-chain/protocol/testutil/constants" + assettypes "github.com/dydxprotocol/v4-chain/protocol/x/assets/types" + clobtypes "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" + satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" + "github.com/stretchr/testify/require" +) + +// Test helper functions for leverage e2e tests + +// setupLeverageTest creates a test app with the necessary state for leverage testing +func setupLeverageTest(t *testing.T) *testapp.TestApp { + tApp := testapp.NewTestAppBuilder(t).Build() + return tApp +} + +// configureLeverage sets leverage for a subaccount and perpetual +func configureLeverage( + t *testing.T, + tApp *testapp.TestApp, + ctx sdk.Context, + subaccountId satypes.SubaccountId, + perpetualId uint32, + custom_imf_ppm uint32, +) { + leverageMap := map[uint32]uint32{ + perpetualId: custom_imf_ppm, + } + + err := tApp.App.SubaccountsKeeper.UpdateLeverage(ctx, &subaccountId, leverageMap) + require.NoError(t, err) +} + +// createSubaccountWithBalance creates a subaccount with specified USDC balance +func createSubaccountWithBalance( + tApp *testapp.TestApp, + ctx sdk.Context, + subaccountId satypes.SubaccountId, + usdcBalance *big.Int, +) { + subaccount := satypes.Subaccount{ + Id: &subaccountId, + AssetPositions: []*satypes.AssetPosition{ + { + AssetId: assettypes.AssetUsdc.Id, + Quantums: dtypes.NewIntFromBigInt(usdcBalance), + }, + }, + } + + tApp.App.SubaccountsKeeper.SetSubaccount(ctx, subaccount) +} + +// TestLeverageKeeperSetup verifies that the LeverageKeeper is properly wired up +func TestLeverageKeeperSetup(t *testing.T) { + tApp := setupLeverageTest(t) + ctx := tApp.InitChain() + + // Test that the SubaccountsKeeper has a non-nil LeverageKeeper + // We can't directly access the leverageKeeper field since it's private, + // but we can test that leverage-aware operations work + + subaccountId := constants.Alice_Num0 + perpetualId := uint32(0) + custom_imf_ppm := uint32(50_000) + + // Configure leverage first + configureLeverage(t, tApp, ctx, subaccountId, perpetualId, custom_imf_ppm) + + // Verify leverage was set + leverageMap, exists := tApp.App.SubaccountsKeeper.GetLeverage(ctx, &subaccountId) + require.True(t, exists) + require.Equal(t, custom_imf_ppm, leverageMap[perpetualId]) + + // Create a subaccount with some balance + createSubaccountWithBalance(tApp, ctx, subaccountId, big.NewInt(1000_000_000)) + + // Test that CanUpdateSubaccounts works (this internally uses the leverageKeeper) + updates := []satypes.Update{ + { + SubaccountId: subaccountId, + AssetUpdates: []satypes.AssetUpdate{ + { + AssetId: assettypes.AssetUsdc.Id, + BigQuantumsDelta: big.NewInt(-100_000_000), // Spend $100 + }, + }, + PerpetualUpdates: []satypes.PerpetualUpdate{ + { + PerpetualId: perpetualId, + BigQuantumsDelta: big.NewInt(1_000_000), // Small position + }, + }, + }, + } + + // This should work without panicking (leverageKeeper should not be nil) + success, results, err := tApp.App.SubaccountsKeeper.CanUpdateSubaccounts( + ctx, + updates, + satypes.CollatCheck, + ) + + require.NoError(t, err, "CanUpdateSubaccounts should not error") + require.NotNil(t, results, "Results should not be nil") + require.Len(t, results, 1, "Should have one result") + + t.Logf("✅ LeverageKeeper is properly wired up") + t.Logf(" CanUpdateSubaccounts success: %v", success) + t.Logf(" Update result: %v", results[0]) +} + +// TestLeverageBasicOrderPlacement tests basic order placement with leverage configuration +func TestLeverageBasicOrderPlacement(t *testing.T) { + tApp := setupLeverageTest(t) + ctx := tApp.InitChain() + + // Test parameters + subaccountId := constants.Alice_Num0 + perpetualId := uint32(0) // BTC-USD + custom_imf_ppm := uint32(100_000) // 10x leverage + initialBalance := big.NewInt(1000_000_000) // $1000 USDC (6 decimals) + + // Set up subaccount with initial balance + createSubaccountWithBalance(tApp, ctx, subaccountId, initialBalance) + + // Configure leverage + configureLeverage(t, tApp, ctx, subaccountId, perpetualId, custom_imf_ppm) + + // Verify leverage was set correctly + leverageMap, exists := tApp.App.SubaccountsKeeper.GetLeverage(ctx, &subaccountId) + require.True(t, exists) + require.Equal(t, custom_imf_ppm, leverageMap[perpetualId]) + + t.Logf("✅ Successfully configured and verified %dx leverage for subaccount", custom_imf_ppm) + t.Logf(" Subaccount: %v", subaccountId) + t.Logf(" Perpetual ID: %d", perpetualId) + t.Logf(" Initial balance: $%s", new(big.Int).Div(initialBalance, big.NewInt(1_000_000))) +} + +// TestLeverageConfiguration tests basic leverage configuration functionality +func TestLeverageConfiguration(t *testing.T) { + tApp := setupLeverageTest(t) + ctx := tApp.InitChain() + + subaccountId := constants.Alice_Num0 + perpetualId := uint32(0) + + testCases := []struct { + name string + custom_imf_ppm uint32 + }{ + {"2x Leverage", 500_000}, + {"10x Leverage", 100_000}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Configure leverage + configureLeverage(t, tApp, ctx, subaccountId, perpetualId, tc.custom_imf_ppm) + + // Verify leverage was set correctly + leverageMap, exists := tApp.App.SubaccountsKeeper.GetLeverage(ctx, &subaccountId) + require.True(t, exists) + require.Equal(t, tc.custom_imf_ppm, leverageMap[perpetualId]) + + t.Logf("✅ Successfully configured %dx leverage", tc.custom_imf_ppm) + }) + } +} + +func TestOrderPlacementFailsWithLeverageConfigured(t *testing.T) { + tApp := testapp.NewTestAppBuilder(t).Build() + ctx := tApp.InitChain() + + // Verify Alice and Bob have identical subaccounts + gotAlice := tApp.App.SubaccountsKeeper.GetSubaccount(ctx, constants.Alice_Num0) + gotBob := tApp.App.SubaccountsKeeper.GetSubaccount(ctx, constants.Bob_Num0) + require.Equal(t, gotAlice.AssetPositions, gotBob.AssetPositions, "Alice and Bob should have identical asset positions") + + // Configure leverage for Alice: 1x on BTC perpetual + aliceLeverage := &clobtypes.MsgUpdateLeverage{ + SubaccountId: &constants.Alice_Num0, + ClobPairLeverage: []*clobtypes.LeverageEntry{ + { + ClobPairId: 0, + CustomImfPpm: 1_000_000, + }, + }, + } + for _, checkTx := range testapp.MustMakeCheckTxsWithClobMsg( + ctx, + tApp.App, + *aliceLeverage, + ) { + resp := tApp.CheckTx(checkTx) + require.True(t, resp.IsOK(), "Expected Alice's CheckTx to succeed. Response: %+v", resp) + } + + ctx = tApp.AdvanceToBlock(2, testapp.AdvanceToBlockOptions{}) + + // Place orders for both Alice and Bob that would require the entire margin if leverage was unchanged + orderSize := dtypes.NewIntFromBigInt(big.NewInt(5_500_000_000_000_000)) + + // Use the same price and clob pair as in the other test + price := uint64(2_000_000_000) + + // Bob's order should succeed + bobOrder := &clobtypes.Order{ + OrderId: clobtypes.OrderId{ + SubaccountId: constants.Bob_Num0, + ClientId: 0, + OrderFlags: clobtypes.OrderIdFlags_LongTerm, + ClobPairId: 0, + }, + Side: clobtypes.Order_SIDE_BUY, + Quantums: orderSize.BigInt().Uint64(), + Subticks: price, + GoodTilOneof: &clobtypes.Order_GoodTilBlockTime{ + GoodTilBlockTime: uint32(ctx.BlockTime().Unix() + 100), + }, + } + for _, checkTx := range testapp.MustMakeCheckTxsWithClobMsg( + ctx, + tApp.App, + *clobtypes.NewMsgPlaceOrder(*bobOrder), + ) { + resp := tApp.CheckTx(checkTx) + require.True(t, resp.IsOK(), "Expected Bob's CheckTx to succeed. Response: %+v", resp) + } + + bobSubaccount := tApp.App.SubaccountsKeeper.GetSubaccount(ctx, constants.Bob_Num0) + require.True(t, bobSubaccount.AssetPositions != nil, "Bob should have a subaccount") + + // Alice's order should fail due to leverage config + aliceOrder := &clobtypes.Order{ + OrderId: clobtypes.OrderId{ + SubaccountId: constants.Alice_Num0, + ClientId: 0, + OrderFlags: clobtypes.OrderIdFlags_LongTerm, + ClobPairId: 0, + }, + Side: clobtypes.Order_SIDE_BUY, + Quantums: orderSize.BigInt().Uint64(), + Subticks: price, + GoodTilOneof: &clobtypes.Order_GoodTilBlockTime{ + GoodTilBlockTime: uint32(ctx.BlockTime().Unix() + 100), + }, + } + for _, checkTx := range testapp.MustMakeCheckTxsWithClobMsg( + ctx, + tApp.App, + *clobtypes.NewMsgPlaceOrder(*aliceOrder), + ) { + resp := tApp.CheckTx(checkTx) + require.False(t, resp.IsOK(), "Expected Alice's CheckTx to fail due to leverage. Response: %+v", resp) + } +} diff --git a/protocol/x/clob/keeper/liquidations.go b/protocol/x/clob/keeper/liquidations.go index aa4f9636d9..9b979f536f 100644 --- a/protocol/x/clob/keeper/liquidations.go +++ b/protocol/x/clob/keeper/liquidations.go @@ -456,12 +456,14 @@ func (k Keeper) GetBankruptcyPriceInQuoteQuantums( marketPrice, liquidityTier, psBig, + 0, // No custom IMF for liquidations ) riskPosNew := perplib.GetPositionNetNotionalValueAndMarginRequirements( perpetual, marketPrice, liquidityTier, new(big.Int).Add(psBig, deltaQuantums), + 0, // No custom IMF for liquidations ) // `DMMR = PMMRAD - PMMR`, where `PMMRAD` is the perpetual's maintenance margin requirement // with a position size of `PS + deltaQuantums`. @@ -546,6 +548,7 @@ func (k Keeper) GetFillablePrice( marketPrice, liquidityTier, psBig, + 0, // No custom IMF for liquidations ) riskTotal, err := k.subaccountsKeeper.GetNetCollateralAndMarginRequirements( diff --git a/protocol/x/clob/types/clob_keeper.go b/protocol/x/clob/types/clob_keeper.go index 87167cd24f..8d307660f8 100644 --- a/protocol/x/clob/types/clob_keeper.go +++ b/protocol/x/clob/types/clob_keeper.go @@ -158,7 +158,6 @@ type ClobKeeper interface { // Leverage methods UpdateLeverage(ctx sdk.Context, subaccountId *satypes.SubaccountId, perpetualLeverage map[uint32]uint32) error - GetLeverage(ctx sdk.Context, subaccountId *satypes.SubaccountId) (map[uint32]uint32, bool) RateLimitUpdateLeverage(ctx sdk.Context, msg *MsgUpdateLeverage) error - GetMaxLeverageForPerpetual(ctx sdk.Context, perpetualId uint32) (uint32, error) + GetSubaccountsKeeper() SubaccountsKeeper } diff --git a/protocol/x/clob/types/expected_keepers.go b/protocol/x/clob/types/expected_keepers.go index fbc77e831d..cd7bcef9b4 100644 --- a/protocol/x/clob/types/expected_keepers.go +++ b/protocol/x/clob/types/expected_keepers.go @@ -105,6 +105,26 @@ type SubaccountsKeeper interface { revSharesForFill revsharetypes.RevSharesForFill, fillForProcess FillForProcess, ) error + + // Leverage methods + SetLeverage( + ctx sdk.Context, + subaccountId *satypes.SubaccountId, + leverageMap map[uint32]uint32, + ) + GetLeverage( + ctx sdk.Context, + subaccountId *satypes.SubaccountId, + ) (map[uint32]uint32, bool) + UpdateLeverage( + ctx sdk.Context, + subaccountId *satypes.SubaccountId, + perpetualLeverage map[uint32]uint32, + ) error + GetMinImfForPerpetual( + ctx sdk.Context, + perpetualId uint32, + ) (uint32, error) } type AssetsKeeper interface { diff --git a/protocol/x/clob/types/leverage.go b/protocol/x/clob/types/leverage.go index 56c0e0e30f..2a40f030b6 100644 --- a/protocol/x/clob/types/leverage.go +++ b/protocol/x/clob/types/leverage.go @@ -28,10 +28,10 @@ func ValidateUpdateLeverageMsg(ctx sdk.Context, msg *MsgUpdateLeverage, clobKeep return errorsmod.Wrap(ErrInvalidLeverage, "leverage entry cannot be nil") } - if entry.Leverage == 0 { + if entry.CustomImfPpm == 0 || entry.CustomImfPpm > 1_000_000 { return errorsmod.Wrap( ErrInvalidLeverage, - fmt.Sprintf("leverage for clob pair %d cannot be zero", entry.ClobPairId), + fmt.Sprintf("imf ppm for clob pair %d must be between (0, 1,000,000]", entry.ClobPairId), ) } @@ -68,7 +68,7 @@ func ValidateAndConstructPerpetualLeverageMap( for _, entry := range msg.ClobPairLeverage { clob, _ := clobKeeper.GetClobPair(ctx, ClobPairId(entry.ClobPairId)) perpetualId := clob.MustGetPerpetualId() - perpetualLeverageMap[perpetualId] = entry.Leverage + perpetualLeverageMap[perpetualId] = entry.CustomImfPpm } return perpetualLeverageMap, nil diff --git a/protocol/x/clob/types/query.pb.go b/protocol/x/clob/types/query.pb.go index a4b8757d70..ec414e7561 100644 --- a/protocol/x/clob/types/query.pb.go +++ b/protocol/x/clob/types/query.pb.go @@ -954,8 +954,8 @@ func (m *QueryLeverageResponse) GetClobPairLeverage() []*ClobPairLeverageInfo { type ClobPairLeverageInfo struct { // The clob pair ID. ClobPairId uint32 `protobuf:"varint,1,opt,name=clob_pair_id,json=clobPairId,proto3" json:"clob_pair_id,omitempty"` - // The leverage amount. - Leverage uint32 `protobuf:"varint,2,opt,name=leverage,proto3" json:"leverage,omitempty"` + // The user selected imf. + CustomImfPpm uint32 `protobuf:"varint,2,opt,name=custom_imf_ppm,json=customImfPpm,proto3" json:"custom_imf_ppm,omitempty"` } func (m *ClobPairLeverageInfo) Reset() { *m = ClobPairLeverageInfo{} } @@ -998,9 +998,9 @@ func (m *ClobPairLeverageInfo) GetClobPairId() uint32 { return 0 } -func (m *ClobPairLeverageInfo) GetLeverage() uint32 { +func (m *ClobPairLeverageInfo) GetCustomImfPpm() uint32 { if m != nil { - return m.Leverage + return m.CustomImfPpm } return 0 } @@ -1610,127 +1610,128 @@ func init() { func init() { proto.RegisterFile("dydxprotocol/clob/query.proto", fileDescriptor_3365c195b25c5bc0) } var fileDescriptor_3365c195b25c5bc0 = []byte{ - // 1917 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x58, 0x41, 0x6c, 0xdc, 0xc6, - 0x15, 0x5d, 0x4a, 0xb2, 0x2d, 0xfd, 0x95, 0x14, 0x69, 0x2c, 0x3b, 0xca, 0x4a, 0x5e, 0xc9, 0x74, - 0x2c, 0x69, 0x1d, 0x7b, 0x29, 0x2b, 0x46, 0x90, 0xda, 0x45, 0x0a, 0xcb, 0xa9, 0x2d, 0xa1, 0x56, - 0xa2, 0xd0, 0x8a, 0x63, 0xb4, 0x01, 0x08, 0x2e, 0x39, 0xbb, 0x1a, 0x88, 0xe4, 0xac, 0xc8, 0xe1, - 0x56, 0x82, 0x61, 0x14, 0xe8, 0x21, 0x97, 0xb6, 0x40, 0x81, 0x1c, 0x7a, 0x28, 0x7a, 0xea, 0xb9, - 0x40, 0x2f, 0x3d, 0x16, 0x6d, 0x6f, 0x39, 0x06, 0x68, 0x0f, 0x3d, 0x14, 0x45, 0x61, 0xf7, 0xdc, - 0x4b, 0x81, 0x9e, 0x0b, 0xce, 0x0c, 0xb9, 0xe4, 0x92, 0x5c, 0xad, 0x7d, 0x91, 0x76, 0xfe, 0xfc, - 0x79, 0xf3, 0xfe, 0xfc, 0x3f, 0xf3, 0xff, 0x27, 0x5c, 0xb1, 0x4f, 0xed, 0x93, 0xae, 0x4f, 0x19, - 0xb5, 0xa8, 0xa3, 0x59, 0x0e, 0x6d, 0x69, 0xc7, 0x21, 0xf6, 0x4f, 0x9b, 0x5c, 0x86, 0xe6, 0xd3, - 0xd3, 0xcd, 0x68, 0xba, 0xb6, 0xd0, 0xa1, 0x1d, 0xca, 0x45, 0x5a, 0xf4, 0x4b, 0x28, 0xd6, 0x96, - 0x3b, 0x94, 0x76, 0x1c, 0xac, 0x99, 0x5d, 0xa2, 0x99, 0x9e, 0x47, 0x99, 0xc9, 0x08, 0xf5, 0x02, - 0x39, 0x7b, 0xc3, 0xa2, 0x81, 0x4b, 0x03, 0xad, 0x65, 0x06, 0x58, 0xe0, 0x6b, 0xbd, 0xdb, 0x2d, - 0xcc, 0xcc, 0xdb, 0x5a, 0xd7, 0xec, 0x10, 0x8f, 0x2b, 0x4b, 0x5d, 0x2d, 0xcf, 0xa8, 0xe5, 0x50, - 0xeb, 0xc8, 0xf0, 0x4d, 0x86, 0x0d, 0x87, 0xb8, 0x84, 0x19, 0x16, 0xf5, 0xda, 0xa4, 0x23, 0x17, - 0x5c, 0xcd, 0x2f, 0x88, 0xfe, 0x18, 0x5d, 0x93, 0xf8, 0x52, 0x65, 0x33, 0xaf, 0x82, 0x8f, 0x43, - 0xc2, 0x4e, 0x0d, 0x46, 0xb0, 0x5f, 0x04, 0x5a, 0x70, 0x2e, 0xd4, 0xb7, 0x71, 0x0c, 0xb8, 0x92, - 0x9f, 0x76, 0x4d, 0x66, 0x1d, 0xe2, 0xd8, 0xe2, 0xf7, 0xf2, 0x0a, 0x0e, 0x39, 0x0e, 0x89, 0x2d, - 0xce, 0x25, 0xbb, 0xd9, 0x52, 0x01, 0x1a, 0xee, 0xc9, 0xc9, 0x8f, 0x32, 0x93, 0xc4, 0xb3, 0xf1, - 0x09, 0xf6, 0x35, 0xda, 0x6e, 0x1b, 0xd6, 0xa1, 0x49, 0x3c, 0x23, 0xec, 0xda, 0x26, 0xc3, 0x41, - 0x5e, 0x22, 0xd7, 0x6f, 0x64, 0xd6, 0x07, 0x61, 0xcb, 0xb4, 0x2c, 0x1a, 0x7a, 0x2c, 0xd0, 0x02, - 0xe6, 0x63, 0xd3, 0x25, 0x5e, 0x4c, 0xa3, 0x51, 0xae, 0x99, 0xfc, 0x96, 0xaa, 0xd7, 0x32, 0xaa, - 0x5d, 0x9f, 0x58, 0x38, 0x87, 0xa7, 0x36, 0xe0, 0xed, 0xcf, 0x22, 0x5f, 0x3f, 0xc2, 0xec, 0x81, - 0x43, 0x5b, 0xfb, 0x26, 0xf1, 0x75, 0x7c, 0x1c, 0xe2, 0x80, 0xa1, 0x59, 0x18, 0x23, 0xf6, 0xa2, - 0xb2, 0xaa, 0x6c, 0xcc, 0xe8, 0x63, 0xc4, 0x56, 0xbf, 0x80, 0x4b, 0x5c, 0xb5, 0xaf, 0x17, 0x74, - 0xa9, 0x17, 0x60, 0xf4, 0x11, 0x4c, 0x25, 0xce, 0xe4, 0xfa, 0xd5, 0xad, 0xa5, 0x66, 0x2e, 0x28, - 0x9b, 0xf1, 0xba, 0xed, 0x89, 0x6f, 0xfe, 0xb9, 0x52, 0xd1, 0x27, 0x2d, 0x39, 0x56, 0x4d, 0xc9, - 0xe1, 0xbe, 0xe3, 0x0c, 0x72, 0x78, 0x08, 0xd0, 0x0f, 0x3e, 0x89, 0xbd, 0xd6, 0x14, 0x91, 0xda, - 0x8c, 0x22, 0xb5, 0x29, 0x6e, 0x82, 0x8c, 0xd4, 0xe6, 0xbe, 0xd9, 0xc1, 0x72, 0xad, 0x9e, 0x5a, - 0xa9, 0xfe, 0x56, 0x81, 0xc5, 0x0c, 0xf9, 0xfb, 0x8e, 0x53, 0xc6, 0x7f, 0xfc, 0x35, 0xf9, 0xa3, - 0x47, 0x19, 0x92, 0x63, 0x9c, 0xe4, 0xfa, 0x99, 0x24, 0xc5, 0xe6, 0x19, 0x96, 0xff, 0x50, 0x60, - 0x65, 0x0f, 0xf7, 0x3e, 0xa1, 0x36, 0x3e, 0xa0, 0xd1, 0xdf, 0x07, 0xa6, 0x63, 0x85, 0x0e, 0x9f, - 0x8c, 0x4f, 0xe4, 0x4b, 0xb8, 0x2c, 0xae, 0x5a, 0xd7, 0xa7, 0x5d, 0x1a, 0x60, 0xdf, 0x90, 0x41, - 0x9d, 0x9c, 0x4e, 0x9e, 0xf9, 0x53, 0xd3, 0x89, 0x82, 0x9a, 0xfa, 0x7b, 0xb8, 0xb7, 0x27, 0xb4, - 0xf5, 0x05, 0x8e, 0xb2, 0x2f, 0x41, 0xa4, 0x14, 0xfd, 0x08, 0x2e, 0xf5, 0x62, 0x65, 0xc3, 0xc5, - 0x3d, 0xc3, 0xc5, 0xcc, 0x27, 0x56, 0x90, 0x58, 0x95, 0x07, 0xcf, 0x10, 0xde, 0x13, 0xea, 0xfa, - 0xc5, 0x5e, 0x7a, 0x4b, 0x21, 0x54, 0xff, 0xa3, 0xc0, 0x6a, 0xb9, 0x79, 0xd2, 0x19, 0x1d, 0xb8, - 0xe0, 0xe3, 0x20, 0x74, 0x58, 0x20, 0x5d, 0xf1, 0xe8, 0xac, 0x3d, 0x0b, 0x50, 0x22, 0x85, 0xfb, - 0x9e, 0xfd, 0x94, 0x3a, 0xa1, 0x8b, 0xf7, 0xb1, 0x1f, 0xb9, 0x4e, 0xba, 0x2d, 0x46, 0xaf, 0x99, - 0x70, 0xb1, 0x40, 0x0b, 0xad, 0xc2, 0x74, 0x12, 0x0c, 0x46, 0x12, 0xff, 0x10, 0x3b, 0x7b, 0xd7, - 0x46, 0x73, 0x30, 0xee, 0xe2, 0x1e, 0x3f, 0x91, 0x31, 0x3d, 0xfa, 0x89, 0x2e, 0xc3, 0xf9, 0x1e, - 0x07, 0x59, 0x1c, 0x5f, 0x55, 0x36, 0x26, 0x74, 0x39, 0x52, 0x6f, 0xc0, 0x06, 0x0f, 0xba, 0xef, - 0xf3, 0x77, 0xec, 0x80, 0x60, 0xff, 0x71, 0xf4, 0x8a, 0x3d, 0xe0, 0xef, 0x4a, 0xe8, 0xa7, 0xfd, - 0xaa, 0xfe, 0x5a, 0x81, 0xc6, 0x08, 0xca, 0xf2, 0x94, 0x3c, 0x58, 0x2c, 0x7b, 0x1c, 0x65, 0x1c, - 0x68, 0x05, 0xc7, 0x36, 0x0c, 0x5a, 0x1e, 0xcf, 0x25, 0x5c, 0xa4, 0xa3, 0x36, 0x60, 0x9d, 0x93, - 0xdb, 0x8e, 0x82, 0x46, 0x37, 0x19, 0x2e, 0x37, 0xe4, 0x57, 0x8a, 0xb4, 0x7a, 0xa8, 0xae, 0xb4, - 0xe3, 0x08, 0xde, 0x2e, 0x49, 0x1c, 0xd2, 0x8c, 0x66, 0x81, 0x19, 0x43, 0x80, 0xa5, 0x15, 0x22, - 0xb8, 0x07, 0x54, 0xd4, 0x67, 0xf0, 0x0e, 0x27, 0xf6, 0x84, 0x99, 0x0c, 0xb7, 0x43, 0xe7, 0xd3, - 0x28, 0x59, 0xc4, 0xf7, 0xea, 0x1e, 0x4c, 0xf2, 0xe4, 0x11, 0xfb, 0xbc, 0xba, 0x55, 0x2b, 0xd8, - 0x9a, 0x2f, 0xd9, 0xb5, 0xe3, 0x58, 0xa2, 0x62, 0xa8, 0xfe, 0x41, 0x81, 0x5a, 0x11, 0xb4, 0xb4, - 0xf2, 0x19, 0xbc, 0x25, 0xb0, 0xbb, 0x8e, 0x69, 0x61, 0x17, 0x7b, 0x4c, 0x6e, 0xd1, 0x28, 0xd8, - 0xe2, 0x31, 0xf5, 0x3a, 0x07, 0xd8, 0x77, 0x39, 0xc4, 0x7e, 0xbc, 0x40, 0xee, 0x38, 0x4b, 0x33, - 0x52, 0xb4, 0x02, 0xd5, 0x36, 0x71, 0x1c, 0xc3, 0x74, 0xa3, 0x87, 0x9f, 0xc7, 0xe4, 0x84, 0x0e, - 0x91, 0xe8, 0x3e, 0x97, 0xa0, 0x65, 0x98, 0x62, 0x3e, 0xe9, 0x74, 0xb0, 0x8f, 0x6d, 0x1e, 0x9d, - 0x93, 0x7a, 0x5f, 0xa0, 0xae, 0xc3, 0x75, 0x4e, 0xfb, 0x71, 0x2a, 0xed, 0x15, 0x3a, 0xf5, 0x2b, - 0x05, 0xd6, 0xce, 0xd2, 0x94, 0xc6, 0x7e, 0x09, 0x17, 0x0b, 0xb2, 0xa8, 0x34, 0xf8, 0x7a, 0x91, - 0xc1, 0x39, 0x48, 0x69, 0x2c, 0x72, 0x72, 0x33, 0xea, 0xb2, 0x3c, 0xe8, 0x4f, 0xf0, 0x49, 0x92, - 0xb0, 0x76, 0xed, 0x98, 0xe6, 0x0e, 0x2c, 0x15, 0xce, 0x4a, 0x6a, 0x0d, 0x98, 0xf7, 0xf0, 0x09, - 0x33, 0x0a, 0x2e, 0xf8, 0xac, 0x97, 0x59, 0xa2, 0x7e, 0x0c, 0x0b, 0xc2, 0x5e, 0xdc, 0xc3, 0x7e, - 0x3f, 0xa9, 0xa0, 0x05, 0x38, 0x47, 0x7f, 0xec, 0x61, 0x91, 0xe7, 0xa6, 0x74, 0x31, 0x88, 0x1e, - 0x00, 0x2f, 0x74, 0x5b, 0xd8, 0xe7, 0x1e, 0x98, 0xd1, 0xe5, 0x48, 0xf5, 0x64, 0xca, 0xec, 0xa3, - 0x48, 0x26, 0x9f, 0x03, 0xea, 0x93, 0x70, 0xe4, 0xac, 0x7c, 0xf0, 0xd6, 0x87, 0xe4, 0x9e, 0x18, - 0x68, 0xd7, 0x6b, 0x53, 0x7d, 0xce, 0x1a, 0x90, 0xaa, 0x07, 0xb0, 0x50, 0xa4, 0x39, 0xc2, 0xa3, - 0x56, 0x83, 0xc9, 0x84, 0x86, 0xb0, 0x21, 0x19, 0xab, 0xff, 0x55, 0xe0, 0xca, 0x13, 0x5e, 0x37, - 0xf0, 0x98, 0x6c, 0x51, 0x7a, 0xf4, 0xb9, 0x28, 0x5f, 0xe2, 0x53, 0xc9, 0xe3, 0x8f, 0x0f, 0xe0, - 0xef, 0xc1, 0x6c, 0xbf, 0x40, 0x31, 0x88, 0x1d, 0x65, 0x94, 0xf1, 0x7c, 0xba, 0x4a, 0x15, 0x34, - 0xcd, 0x27, 0xc9, 0xef, 0x5d, 0x5b, 0x9f, 0x09, 0x52, 0xa3, 0x00, 0x5d, 0x01, 0x70, 0x4d, 0xff, - 0x08, 0x0b, 0xa8, 0x71, 0xbe, 0xdd, 0x94, 0x90, 0x44, 0xd3, 0xdb, 0x50, 0x6f, 0x13, 0x87, 0x61, - 0xdf, 0xe0, 0xf7, 0x25, 0x30, 0x5a, 0xa7, 0x46, 0x66, 0xfb, 0xc5, 0x09, 0x7e, 0x15, 0x6a, 0x42, - 0x8b, 0x9b, 0x15, 0x6c, 0x9f, 0xa6, 0x77, 0x54, 0x4d, 0xa8, 0x97, 0x19, 0x2d, 0x9d, 0xf8, 0x3d, - 0xb8, 0x20, 0xcb, 0x38, 0xe9, 0xb9, 0x95, 0x02, 0xcf, 0x09, 0x0c, 0xb1, 0x34, 0x7e, 0x36, 0xe4, - 0x2a, 0xf5, 0x7f, 0xe3, 0x30, 0x9d, 0x9e, 0x47, 0x57, 0x61, 0x5a, 0x3c, 0x87, 0x87, 0x98, 0x74, - 0x0e, 0x99, 0xf4, 0x53, 0x95, 0xcb, 0x76, 0xb8, 0x08, 0x2d, 0xc1, 0x14, 0x3e, 0xc1, 0x96, 0xe1, - 0x52, 0x3b, 0xf1, 0x54, 0x24, 0xd8, 0xa3, 0x76, 0x14, 0x56, 0x73, 0x34, 0x66, 0x2b, 0x4b, 0x4c, - 0x7e, 0xe9, 0xab, 0x5b, 0x1b, 0xa5, 0xd4, 0x06, 0xcc, 0xdb, 0xa9, 0xe8, 0x6f, 0xd1, 0xac, 0x28, - 0x2a, 0x70, 0xc4, 0xfb, 0x15, 0x3d, 0x2c, 0xfc, 0xe8, 0x8a, 0xeb, 0x8c, 0x01, 0xc0, 0x87, 0xc4, - 0x71, 0x76, 0x2a, 0xfa, 0x14, 0x5f, 0x1b, 0x0d, 0xd0, 0x43, 0xa8, 0x32, 0xf3, 0x28, 0x76, 0xcb, - 0xe2, 0x39, 0x8e, 0x74, 0xad, 0x14, 0xe9, 0x20, 0xd2, 0xe5, 0x70, 0x3b, 0x15, 0x1d, 0x58, 0x32, - 0x42, 0x06, 0xcc, 0xa7, 0xdc, 0x29, 0x0d, 0x3d, 0xcf, 0xd1, 0x36, 0x87, 0x04, 0x14, 0x07, 0xed, - 0x3b, 0x39, 0x31, 0x78, 0x2e, 0x18, 0x90, 0xa1, 0x1f, 0xc0, 0x34, 0x2f, 0x98, 0x63, 0xec, 0x0b, - 0x45, 0x36, 0x8b, 0x92, 0x5a, 0xc2, 0xee, 0x47, 0x83, 0x04, 0xb1, 0xda, 0xed, 0x0f, 0xb7, 0xe7, - 0x60, 0x56, 0xc0, 0x18, 0x2e, 0x0e, 0x82, 0xe8, 0x46, 0xfd, 0x42, 0x81, 0x4b, 0x85, 0xa7, 0x1f, - 0xdd, 0xc3, 0xc0, 0x33, 0xbb, 0xc1, 0x21, 0x15, 0xde, 0x9f, 0xd4, 0x93, 0x31, 0x7a, 0xd6, 0x8f, - 0x37, 0x71, 0x79, 0x3e, 0xcc, 0xf2, 0x91, 0x7d, 0x47, 0x33, 0xdf, 0x65, 0x7c, 0xda, 0x6e, 0x3f, - 0x88, 0x04, 0x62, 0x93, 0xa7, 0xb7, 0x07, 0x03, 0xf1, 0x77, 0x0a, 0x5c, 0x2c, 0x70, 0x1e, 0xba, - 0x07, 0xfc, 0x0e, 0x8b, 0x12, 0x53, 0x3e, 0xe1, 0xcb, 0x25, 0xcf, 0x13, 0x2f, 0x21, 0x75, 0x5e, - 0x49, 0xf3, 0x9f, 0xe8, 0x03, 0x38, 0x2f, 0x6e, 0x9f, 0x64, 0xbb, 0x58, 0x96, 0x4f, 0x25, 0x1b, - 0xa9, 0x1d, 0x5d, 0x82, 0x54, 0x4e, 0x13, 0xb7, 0x7b, 0x42, 0xaf, 0xf6, 0x93, 0x5a, 0xa0, 0x7e, - 0x35, 0x06, 0x73, 0x83, 0x21, 0x82, 0x36, 0xe1, 0x9c, 0x08, 0x2b, 0xc1, 0xb3, 0x74, 0xbb, 0x9d, - 0x8a, 0x2e, 0x14, 0xd1, 0x33, 0x98, 0x4f, 0xa5, 0x18, 0x19, 0x94, 0x63, 0xa5, 0x99, 0x59, 0xec, - 0x98, 0x4a, 0x57, 0x31, 0xdc, 0x9c, 0x33, 0x20, 0x43, 0x5f, 0x00, 0x4a, 0x05, 0xba, 0x11, 0x30, - 0x93, 0x85, 0x81, 0xbc, 0x8a, 0x8d, 0x11, 0xe2, 0xfd, 0x09, 0x5f, 0xa0, 0xcf, 0xb1, 0x01, 0xc9, - 0xf6, 0x4c, 0xe6, 0x06, 0xa9, 0xbf, 0x57, 0xe0, 0x72, 0xf1, 0xda, 0xe8, 0x18, 0x33, 0x9b, 0xcb, - 0xb7, 0x84, 0xa6, 0x54, 0x6e, 0x01, 0xf2, 0xb1, 0x6b, 0x12, 0x8f, 0x78, 0x1d, 0xe3, 0x38, 0x34, - 0x3d, 0x16, 0xba, 0x81, 0x2c, 0x22, 0xe6, 0x93, 0x99, 0xcf, 0xe4, 0x04, 0xfa, 0x18, 0xea, 0xb4, - 0xcb, 0x88, 0x4b, 0x02, 0x46, 0x2c, 0xd3, 0x71, 0x4e, 0xf9, 0x7b, 0x80, 0xed, 0xfe, 0x52, 0x51, - 0xfe, 0x2e, 0x67, 0xb5, 0x1e, 0x72, 0xa5, 0x18, 0x65, 0xeb, 0x6f, 0xd3, 0x70, 0x8e, 0x27, 0x45, - 0xf4, 0x33, 0x05, 0x26, 0xe3, 0x74, 0x85, 0x6e, 0x14, 0x9c, 0x4a, 0x49, 0x67, 0x5a, 0xdb, 0x28, - 0xd3, 0x1d, 0x6c, 0x4d, 0xd5, 0xc6, 0x4f, 0xff, 0xfa, 0xef, 0xaf, 0xc7, 0xae, 0xa1, 0xab, 0xda, - 0x90, 0x0f, 0x10, 0xda, 0x73, 0x62, 0xbf, 0x40, 0x3f, 0x57, 0xa0, 0x9a, 0xea, 0x0e, 0xcb, 0x09, - 0xe5, 0xdb, 0xd4, 0xda, 0x7b, 0x67, 0x11, 0x4a, 0xb5, 0x9b, 0xea, 0xbb, 0x9c, 0x53, 0x1d, 0x2d, - 0x0f, 0xe3, 0x84, 0xfe, 0xa4, 0xc0, 0x62, 0x59, 0x9b, 0x83, 0xb6, 0x5e, 0xab, 0x27, 0x12, 0x1c, - 0xdf, 0x7f, 0x83, 0x3e, 0x4a, 0xbd, 0xcb, 0xb9, 0xde, 0xb9, 0xab, 0xdc, 0x50, 0x35, 0xad, 0xf0, - 0x0b, 0x88, 0xe1, 0x51, 0x1b, 0x1b, 0x8c, 0x8a, 0xff, 0x56, 0x8a, 0xe4, 0x5f, 0x14, 0x58, 0x1e, - 0xd6, 0x71, 0xa0, 0x7b, 0x65, 0xa7, 0x36, 0x42, 0xbf, 0x54, 0xfb, 0xee, 0x9b, 0x2d, 0x96, 0x76, - 0xad, 0x71, 0xbb, 0x56, 0x51, 0x5d, 0x1b, 0xfa, 0xd5, 0x09, 0xfd, 0x51, 0x81, 0xa5, 0x21, 0xed, - 0x06, 0xba, 0x5b, 0xc6, 0xe2, 0xec, 0x46, 0xa9, 0x76, 0xef, 0x8d, 0xd6, 0x4a, 0x03, 0xae, 0x73, - 0x03, 0x56, 0xd0, 0x95, 0xa1, 0x9f, 0xe2, 0xd0, 0x9f, 0x15, 0x78, 0xa7, 0xb4, 0x64, 0x47, 0x1f, - 0x96, 0x31, 0x38, 0xab, 0x1f, 0xa8, 0x7d, 0xe7, 0x0d, 0x56, 0x4a, 0xe6, 0x4d, 0xce, 0x7c, 0x03, - 0xad, 0x69, 0x23, 0x7d, 0x7e, 0x43, 0x1e, 0xcc, 0x64, 0xba, 0x2a, 0x74, 0xb3, 0x6c, 0xef, 0xa2, - 0xbe, 0xae, 0x76, 0x6b, 0x44, 0x6d, 0xc9, 0xae, 0x82, 0x7e, 0xa3, 0xc0, 0x6c, 0xb6, 0x7f, 0x40, - 0xa5, 0x18, 0x85, 0x5d, 0x48, 0xad, 0x39, 0xaa, 0xba, 0xdc, 0xf3, 0x26, 0x3f, 0x91, 0x35, 0xf4, - 0x6e, 0xc1, 0x89, 0xe4, 0xfa, 0x15, 0xf4, 0xb5, 0x02, 0x93, 0x71, 0x71, 0x8f, 0xd6, 0x4b, 0xfd, - 0x90, 0xed, 0x5b, 0xca, 0x9f, 0xcc, 0xc1, 0xd6, 0x44, 0xbd, 0xc3, 0xd9, 0x34, 0xd1, 0xcd, 0x22, - 0xff, 0x48, 0x65, 0xed, 0x39, 0xef, 0x7b, 0x5e, 0x68, 0xcf, 0x45, 0xa3, 0xf3, 0x02, 0xfd, 0x24, - 0xce, 0x43, 0x83, 0xd5, 0x32, 0xda, 0x1c, 0xb5, 0xf2, 0x8c, 0xbb, 0x89, 0xda, 0xed, 0xd7, 0x58, - 0x21, 0x48, 0x6f, 0x2a, 0xdb, 0xfb, 0xdf, 0xbc, 0xac, 0x2b, 0xdf, 0xbe, 0xac, 0x2b, 0xff, 0x7a, - 0x59, 0x57, 0x7e, 0xf9, 0xaa, 0x5e, 0xf9, 0xf6, 0x55, 0xbd, 0xf2, 0xf7, 0x57, 0xf5, 0xca, 0x0f, - 0x3f, 0xe8, 0x10, 0x76, 0x18, 0xb6, 0x9a, 0x16, 0x75, 0xb3, 0x26, 0xf5, 0xee, 0xdc, 0xe2, 0x65, - 0x92, 0x96, 0x48, 0x4e, 0x84, 0x99, 0xec, 0xb4, 0x8b, 0x83, 0xd6, 0x79, 0x2e, 0x7e, 0xff, 0xff, - 0x01, 0x00, 0x00, 0xff, 0xff, 0xd0, 0xf4, 0xde, 0x0a, 0x7f, 0x17, 0x00, 0x00, + // 1933 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x58, 0x4d, 0x6c, 0xdc, 0xc6, + 0x15, 0x5e, 0x4a, 0xb2, 0x2d, 0xbd, 0x95, 0x14, 0x69, 0x2c, 0x3b, 0xca, 0x4a, 0x5e, 0xc9, 0xb4, + 0xad, 0x1f, 0xc7, 0x5e, 0xca, 0x8a, 0x11, 0xa4, 0x76, 0x91, 0xc2, 0x72, 0x6a, 0x4b, 0xa8, 0x95, + 0x6c, 0x68, 0xc7, 0x31, 0xda, 0xa0, 0x04, 0x97, 0x9c, 0x5d, 0x0d, 0x44, 0x72, 0x28, 0x72, 0xb8, + 0x95, 0x60, 0x18, 0x05, 0x7a, 0xc8, 0xa5, 0x2d, 0x50, 0x20, 0x87, 0x1e, 0x8a, 0x9e, 0x7a, 0x2e, + 0xd0, 0x4b, 0x8f, 0x45, 0xdb, 0x5b, 0x8e, 0x01, 0xda, 0x43, 0x0f, 0x45, 0x51, 0xd8, 0x3d, 0xf7, + 0x52, 0xa0, 0xe7, 0x80, 0x33, 0xc3, 0x5d, 0x72, 0x49, 0xae, 0xd6, 0xbe, 0x48, 0x3b, 0x6f, 0xde, + 0xcf, 0xf7, 0xe6, 0xbd, 0x99, 0xf7, 0x1e, 0xe1, 0x92, 0x7d, 0x62, 0x1f, 0xfb, 0x01, 0x65, 0xd4, + 0xa2, 0x8e, 0x66, 0x39, 0xb4, 0xa5, 0x1d, 0x45, 0x38, 0x38, 0x69, 0x70, 0x1a, 0x9a, 0x4f, 0x6f, + 0x37, 0xe2, 0xed, 0xda, 0x42, 0x87, 0x76, 0x28, 0x27, 0x69, 0xf1, 0x2f, 0xc1, 0x58, 0x5b, 0xee, + 0x50, 0xda, 0x71, 0xb0, 0x66, 0xfa, 0x44, 0x33, 0x3d, 0x8f, 0x32, 0x93, 0x11, 0xea, 0x85, 0x72, + 0xf7, 0xba, 0x45, 0x43, 0x97, 0x86, 0x5a, 0xcb, 0x0c, 0xb1, 0xd0, 0xaf, 0x75, 0x6f, 0xb5, 0x30, + 0x33, 0x6f, 0x69, 0xbe, 0xd9, 0x21, 0x1e, 0x67, 0x96, 0xbc, 0x5a, 0x1e, 0x51, 0xcb, 0xa1, 0xd6, + 0xa1, 0x11, 0x98, 0x0c, 0x1b, 0x0e, 0x71, 0x09, 0x33, 0x2c, 0xea, 0xb5, 0x49, 0x47, 0x0a, 0x5c, + 0xce, 0x0b, 0xc4, 0x7f, 0x0c, 0xdf, 0x24, 0x81, 0x64, 0xd9, 0xca, 0xb3, 0xe0, 0xa3, 0x88, 0xb0, + 0x13, 0x83, 0x11, 0x1c, 0x14, 0x29, 0x2d, 0x38, 0x17, 0x1a, 0xd8, 0x38, 0x51, 0xb8, 0x92, 0xdf, + 0x76, 0x4d, 0x66, 0x1d, 0xe0, 0xc4, 0xe3, 0x77, 0xf3, 0x0c, 0x0e, 0x39, 0x8a, 0x88, 0x2d, 0xce, + 0x25, 0x6b, 0x6c, 0xa9, 0x40, 0x1b, 0xee, 0xca, 0xcd, 0x0f, 0x33, 0x9b, 0xc4, 0xb3, 0xf1, 0x31, + 0x0e, 0x34, 0xda, 0x6e, 0x1b, 0xd6, 0x81, 0x49, 0x3c, 0x23, 0xf2, 0x6d, 0x93, 0xe1, 0x30, 0x4f, + 0x91, 0xf2, 0x1b, 0x19, 0xf9, 0x30, 0x6a, 0x99, 0x96, 0x45, 0x23, 0x8f, 0x85, 0x5a, 0xc8, 0x02, + 0x6c, 0xba, 0xc4, 0x4b, 0x60, 0x6c, 0x96, 0x73, 0xf6, 0x7e, 0x4b, 0xd6, 0x2b, 0x19, 0x56, 0x3f, + 0x20, 0x16, 0xce, 0xe9, 0x53, 0x37, 0xe1, 0xed, 0x4f, 0xe3, 0x58, 0x3f, 0xc4, 0xec, 0xbe, 0x43, + 0x5b, 0x4d, 0x93, 0x04, 0x3a, 0x3e, 0x8a, 0x70, 0xc8, 0xd0, 0x2c, 0x8c, 0x11, 0x7b, 0x51, 0x59, + 0x55, 0x36, 0x66, 0xf4, 0x31, 0x62, 0xab, 0x9f, 0xc3, 0x05, 0xce, 0xda, 0xe7, 0x0b, 0x7d, 0xea, + 0x85, 0x18, 0x7d, 0x08, 0x53, 0xbd, 0x60, 0x72, 0xfe, 0xea, 0xf6, 0x52, 0x23, 0x97, 0x94, 0x8d, + 0x44, 0x6e, 0x67, 0xe2, 0xeb, 0x7f, 0xad, 0x54, 0xf4, 0x49, 0x4b, 0xae, 0x55, 0x53, 0x62, 0xb8, + 0xe7, 0x38, 0x83, 0x18, 0x1e, 0x00, 0xf4, 0x93, 0x4f, 0xea, 0x5e, 0x6b, 0x88, 0x4c, 0x6d, 0xc4, + 0x99, 0xda, 0x10, 0x37, 0x41, 0x66, 0x6a, 0xa3, 0x69, 0x76, 0xb0, 0x94, 0xd5, 0x53, 0x92, 0xea, + 0xef, 0x14, 0x58, 0xcc, 0x80, 0xbf, 0xe7, 0x38, 0x65, 0xf8, 0xc7, 0x5f, 0x13, 0x3f, 0x7a, 0x98, + 0x01, 0x39, 0xc6, 0x41, 0xae, 0x9f, 0x0a, 0x52, 0x18, 0xcf, 0xa0, 0xfc, 0xa7, 0x02, 0x2b, 0xfb, + 0xb8, 0xfb, 0x31, 0xb5, 0xf1, 0x13, 0x1a, 0xff, 0xbd, 0x6f, 0x3a, 0x56, 0xe4, 0xf0, 0xcd, 0xe4, + 0x44, 0xbe, 0x80, 0x8b, 0xe2, 0xaa, 0xf9, 0x01, 0xf5, 0x69, 0x88, 0x03, 0x43, 0x26, 0x75, 0xef, + 0x74, 0xf2, 0xc8, 0x9f, 0x9a, 0x4e, 0x9c, 0xd4, 0x34, 0xd8, 0xc7, 0xdd, 0x7d, 0xc1, 0xad, 0x2f, + 0x70, 0x2d, 0x4d, 0xa9, 0x44, 0x52, 0xd1, 0x8f, 0xe0, 0x42, 0x37, 0x61, 0x36, 0x5c, 0xdc, 0x35, + 0x5c, 0xcc, 0x02, 0x62, 0x85, 0x3d, 0xaf, 0xf2, 0xca, 0x33, 0x80, 0xf7, 0x05, 0xbb, 0x7e, 0xbe, + 0x9b, 0x36, 0x29, 0x88, 0xea, 0x7f, 0x15, 0x58, 0x2d, 0x77, 0x4f, 0x06, 0xa3, 0x03, 0xe7, 0x02, + 0x1c, 0x46, 0x0e, 0x0b, 0x65, 0x28, 0x1e, 0x9e, 0x66, 0xb3, 0x40, 0x4b, 0xcc, 0x70, 0xcf, 0xb3, + 0x9f, 0x52, 0x27, 0x72, 0x71, 0x13, 0x07, 0x71, 0xe8, 0x64, 0xd8, 0x12, 0xed, 0x35, 0x13, 0xce, + 0x17, 0x70, 0xa1, 0x55, 0x98, 0xee, 0x25, 0x83, 0xd1, 0xcb, 0x7f, 0x48, 0x82, 0xbd, 0x67, 0xa3, + 0x39, 0x18, 0x77, 0x71, 0x97, 0x9f, 0xc8, 0x98, 0x1e, 0xff, 0x44, 0x17, 0xe1, 0x6c, 0x97, 0x2b, + 0x59, 0x1c, 0x5f, 0x55, 0x36, 0x26, 0x74, 0xb9, 0x52, 0xaf, 0xc3, 0x06, 0x4f, 0xba, 0xef, 0xf3, + 0x77, 0xec, 0x09, 0xc1, 0xc1, 0xa3, 0xf8, 0x15, 0xbb, 0xcf, 0xdf, 0x95, 0x28, 0x48, 0xc7, 0x55, + 0xfd, 0x8d, 0x02, 0x9b, 0x23, 0x30, 0xcb, 0x53, 0xf2, 0x60, 0xb1, 0xec, 0x71, 0x94, 0x79, 0xa0, + 0x15, 0x1c, 0xdb, 0x30, 0xd5, 0xf2, 0x78, 0x2e, 0xe0, 0x22, 0x1e, 0x75, 0x13, 0xd6, 0x39, 0xb8, + 0x9d, 0x38, 0x69, 0x74, 0x93, 0xe1, 0x72, 0x47, 0x7e, 0xad, 0x48, 0xaf, 0x87, 0xf2, 0x4a, 0x3f, + 0x0e, 0xe1, 0xed, 0x92, 0xc2, 0x21, 0xdd, 0x68, 0x14, 0xb8, 0x31, 0x44, 0xb1, 0xf4, 0x42, 0x24, + 0xf7, 0x00, 0x8b, 0xfa, 0x0c, 0xde, 0xe1, 0xc0, 0x1e, 0x33, 0x93, 0xe1, 0x76, 0xe4, 0x7c, 0x12, + 0x17, 0x8b, 0xe4, 0x5e, 0xdd, 0x85, 0x49, 0x5e, 0x3c, 0x92, 0x98, 0x57, 0xb7, 0x6b, 0x05, 0xa6, + 0xb9, 0xc8, 0x9e, 0x9d, 0xe4, 0x12, 0x15, 0x4b, 0xf5, 0x8f, 0x0a, 0xd4, 0x8a, 0x54, 0x4b, 0x2f, + 0x9f, 0xc1, 0x5b, 0x42, 0xb7, 0xef, 0x98, 0x16, 0x76, 0xb1, 0xc7, 0xa4, 0x89, 0xcd, 0x02, 0x13, + 0x8f, 0xa8, 0xd7, 0x79, 0x82, 0x03, 0x97, 0xab, 0x68, 0x26, 0x02, 0xd2, 0xe2, 0x2c, 0xcd, 0x50, + 0xd1, 0x0a, 0x54, 0xdb, 0xc4, 0x71, 0x0c, 0xd3, 0x8d, 0x1f, 0x7e, 0x9e, 0x93, 0x13, 0x3a, 0xc4, + 0xa4, 0x7b, 0x9c, 0x82, 0x96, 0x61, 0x8a, 0x05, 0xa4, 0xd3, 0xc1, 0x01, 0xb6, 0x79, 0x76, 0x4e, + 0xea, 0x7d, 0x82, 0xba, 0x0e, 0xd7, 0x38, 0xec, 0x47, 0xa9, 0xb2, 0x57, 0x18, 0xd4, 0x2f, 0x15, + 0x58, 0x3b, 0x8d, 0x53, 0x3a, 0xfb, 0x05, 0x9c, 0x2f, 0xa8, 0xa2, 0xd2, 0xe1, 0x6b, 0x45, 0x0e, + 0xe7, 0x54, 0x4a, 0x67, 0x91, 0x93, 0xdb, 0x51, 0x97, 0xe5, 0x41, 0x7f, 0x8c, 0x8f, 0x7b, 0x05, + 0x6b, 0xcf, 0x4e, 0x60, 0xee, 0xc2, 0x52, 0xe1, 0xae, 0x84, 0xb6, 0x09, 0xf3, 0x1e, 0x3e, 0x66, + 0x46, 0xc1, 0x05, 0x9f, 0xf5, 0x32, 0x22, 0xea, 0x47, 0xb0, 0x20, 0xfc, 0xc5, 0x5d, 0x1c, 0xf4, + 0x8b, 0x0a, 0x5a, 0x80, 0x33, 0xf4, 0x27, 0x1e, 0x16, 0x75, 0x6e, 0x4a, 0x17, 0x8b, 0xf8, 0x01, + 0xf0, 0x22, 0xb7, 0x85, 0x03, 0x1e, 0x81, 0x19, 0x5d, 0xae, 0x54, 0x4f, 0x96, 0xcc, 0xbe, 0x16, + 0x89, 0xe4, 0x33, 0x40, 0x7d, 0x10, 0x8e, 0xdc, 0x95, 0x0f, 0xde, 0xfa, 0x90, 0xda, 0x93, 0x28, + 0xda, 0xf3, 0xda, 0x54, 0x9f, 0xb3, 0x06, 0xa8, 0xea, 0x8f, 0x61, 0xa1, 0x88, 0x73, 0x84, 0x47, + 0xed, 0x2a, 0xcc, 0x5a, 0x51, 0xc8, 0xa8, 0x6b, 0x10, 0xb7, 0x6d, 0xf8, 0xbe, 0x2b, 0x3d, 0x99, + 0x16, 0xd4, 0x3d, 0xb7, 0xdd, 0xf4, 0x5d, 0xf5, 0x7f, 0x0a, 0x5c, 0x7a, 0xcc, 0x3b, 0x08, 0x9e, + 0x9d, 0x2d, 0x4a, 0x0f, 0x3f, 0x13, 0x8d, 0x4c, 0x72, 0x3e, 0x79, 0x4b, 0xe3, 0x03, 0x96, 0xf6, + 0x61, 0xb6, 0xdf, 0xaa, 0x18, 0xc4, 0x8e, 0x6b, 0xcb, 0x78, 0xbe, 0x70, 0xa5, 0x5a, 0x9b, 0xc6, + 0xe3, 0xde, 0xef, 0x3d, 0x5b, 0x9f, 0x09, 0x53, 0xab, 0x10, 0x5d, 0x02, 0x70, 0xcd, 0xe0, 0x10, + 0x0b, 0x55, 0xe3, 0xdc, 0xdc, 0x94, 0xa0, 0xc4, 0xdb, 0x3b, 0x50, 0x6f, 0x13, 0x87, 0xe1, 0xc0, + 0xe0, 0x37, 0x27, 0x34, 0x5a, 0x27, 0x46, 0xc6, 0xfc, 0xe2, 0x04, 0xbf, 0x14, 0x35, 0xc1, 0xc5, + 0xdd, 0x0a, 0x77, 0x4e, 0xd2, 0x16, 0x55, 0x13, 0xea, 0x65, 0x4e, 0xcb, 0x70, 0x7e, 0x0f, 0xce, + 0xc9, 0x86, 0x4e, 0xc6, 0x70, 0xa5, 0x20, 0x86, 0x42, 0x87, 0x10, 0x4d, 0x1e, 0x10, 0x29, 0xa5, + 0xfe, 0x7f, 0x1c, 0xa6, 0xd3, 0xfb, 0xe8, 0x32, 0x4c, 0x8b, 0x87, 0xf1, 0x00, 0x93, 0xce, 0x01, + 0x93, 0x11, 0xab, 0x72, 0xda, 0x2e, 0x27, 0xa1, 0x25, 0x98, 0xc2, 0xc7, 0xd8, 0x32, 0x5c, 0x6a, + 0x63, 0x19, 0xad, 0xc9, 0x98, 0xb0, 0x4f, 0xed, 0x38, 0xc1, 0xe6, 0x68, 0x82, 0x56, 0x36, 0x9b, + 0xfc, 0xfa, 0x57, 0xb7, 0x37, 0x4a, 0xa1, 0x0d, 0xb8, 0xb7, 0x5b, 0xd1, 0xdf, 0xa2, 0x59, 0x52, + 0xdc, 0xea, 0x88, 0x97, 0x2c, 0x7e, 0x62, 0xf8, 0xd1, 0x15, 0x77, 0x1c, 0x03, 0x0a, 0x1f, 0x10, + 0xc7, 0xd9, 0xad, 0xe8, 0x53, 0x5c, 0x36, 0x5e, 0xa0, 0x07, 0x50, 0x65, 0xe6, 0x61, 0x12, 0x96, + 0xc5, 0x33, 0x5c, 0xd3, 0x95, 0x52, 0x4d, 0x4f, 0x62, 0x5e, 0xae, 0x6e, 0xb7, 0xa2, 0x03, 0xeb, + 0xad, 0x90, 0x01, 0xf3, 0xa9, 0x70, 0x4a, 0x47, 0xcf, 0x72, 0x6d, 0x5b, 0x43, 0x12, 0x8a, 0x2b, + 0xed, 0x07, 0xb9, 0xe7, 0xf0, 0x5c, 0x38, 0x40, 0x43, 0x3f, 0x80, 0x69, 0xde, 0x3a, 0x27, 0xba, + 0xcf, 0x15, 0xf9, 0x2c, 0x9a, 0x6b, 0xa9, 0xb6, 0x19, 0x2f, 0x7a, 0x1a, 0xab, 0x7e, 0x7f, 0xb9, + 0x33, 0x07, 0xb3, 0x42, 0x8d, 0xe1, 0xe2, 0x30, 0x8c, 0x6f, 0xec, 0x2f, 0x15, 0xb8, 0x50, 0x78, + 0xfa, 0xa8, 0x06, 0x93, 0xa1, 0x67, 0xfa, 0xe1, 0x01, 0x15, 0xd1, 0x9f, 0xd4, 0x7b, 0x6b, 0xf4, + 0xac, 0x9f, 0x6f, 0xe2, 0xf2, 0x7c, 0x90, 0xc5, 0x23, 0x27, 0x90, 0x46, 0x7e, 0xde, 0xf8, 0xa4, + 0xdd, 0xbe, 0x1f, 0x13, 0x84, 0x91, 0xa7, 0xb7, 0x06, 0x13, 0xf1, 0xf7, 0x0a, 0x9c, 0x2f, 0x08, + 0x1e, 0xba, 0x0b, 0xfc, 0x0e, 0x8b, 0x66, 0x53, 0x3e, 0xe6, 0xcb, 0x25, 0x0f, 0x15, 0x6f, 0x26, + 0x75, 0xde, 0x53, 0xf3, 0x9f, 0xe8, 0x7d, 0x38, 0x2b, 0x6e, 0x9f, 0x44, 0xbb, 0x58, 0x56, 0x59, + 0x25, 0x1a, 0xc9, 0x1d, 0x5f, 0x82, 0x54, 0x75, 0x13, 0xb7, 0x7b, 0x42, 0xaf, 0xf6, 0xcb, 0x5b, + 0xa8, 0x7e, 0x39, 0x06, 0x73, 0x83, 0x29, 0x82, 0xb6, 0xe0, 0x8c, 0x48, 0x2b, 0x81, 0xb3, 0xd4, + 0xdc, 0x6e, 0x45, 0x17, 0x8c, 0xe8, 0x19, 0xcc, 0xa7, 0x8a, 0x8d, 0x4c, 0xca, 0xb1, 0xd2, 0x1a, + 0x2d, 0x2c, 0xa6, 0x0a, 0x57, 0xa2, 0x6e, 0xce, 0x19, 0xa0, 0xa1, 0xcf, 0x01, 0xa5, 0x12, 0xdd, + 0x08, 0x99, 0xc9, 0xa2, 0x50, 0x5e, 0xc5, 0xcd, 0x11, 0xf2, 0xfd, 0x31, 0x17, 0xd0, 0xe7, 0xd8, + 0x00, 0x65, 0x67, 0x26, 0x73, 0x83, 0xd4, 0x3f, 0x28, 0x70, 0xb1, 0x58, 0x36, 0x3e, 0xc6, 0x8c, + 0x71, 0xf9, 0x96, 0xd0, 0x14, 0xcb, 0x4d, 0x40, 0x01, 0x76, 0x4d, 0xe2, 0x11, 0xaf, 0x63, 0x1c, + 0x45, 0xa6, 0xc7, 0x22, 0x37, 0x94, 0xed, 0xc4, 0x7c, 0x6f, 0xe7, 0x53, 0xb9, 0x81, 0x3e, 0x82, + 0x3a, 0xf5, 0x19, 0x71, 0x49, 0xc8, 0x88, 0x65, 0x3a, 0xce, 0x09, 0x7f, 0x0f, 0xb0, 0xdd, 0x17, + 0x15, 0x8d, 0xf0, 0x72, 0x96, 0xeb, 0x01, 0x67, 0x4a, 0xb4, 0x6c, 0xff, 0x7d, 0x1a, 0xce, 0xf0, + 0xf2, 0x88, 0x7e, 0xae, 0xc0, 0x64, 0x52, 0xb8, 0xd0, 0xf5, 0x82, 0x53, 0x29, 0x99, 0x51, 0x6b, + 0x1b, 0x65, 0xbc, 0x83, 0x43, 0xaa, 0xba, 0xf9, 0xb3, 0xbf, 0xfd, 0xe7, 0xab, 0xb1, 0x2b, 0xe8, + 0xb2, 0x36, 0xe4, 0x53, 0x84, 0xf6, 0x9c, 0xd8, 0x2f, 0xd0, 0x2f, 0x14, 0xa8, 0xa6, 0xe6, 0xc4, + 0x72, 0x40, 0xf9, 0x81, 0xb5, 0xf6, 0xee, 0x69, 0x80, 0x52, 0x83, 0xa7, 0x7a, 0x95, 0x63, 0xaa, + 0xa3, 0xe5, 0x61, 0x98, 0xd0, 0x9f, 0x15, 0x58, 0x2c, 0x1b, 0x78, 0xd0, 0xf6, 0x6b, 0x4d, 0x47, + 0x02, 0xe3, 0x7b, 0x6f, 0x30, 0x51, 0xa9, 0x77, 0x38, 0xd6, 0xdb, 0x77, 0x94, 0xeb, 0xaa, 0xa6, + 0x15, 0x7e, 0x0b, 0x31, 0x3c, 0x6a, 0x63, 0x83, 0x51, 0xf1, 0xdf, 0x4a, 0x81, 0xfc, 0xab, 0x02, + 0xcb, 0xc3, 0x66, 0x0f, 0x74, 0xb7, 0xec, 0xd4, 0x46, 0x98, 0x9c, 0x6a, 0xdf, 0x7d, 0x33, 0x61, + 0xe9, 0xd7, 0x1a, 0xf7, 0x6b, 0x15, 0xd5, 0xb5, 0xa1, 0xdf, 0x9f, 0xd0, 0x9f, 0x14, 0x58, 0x1a, + 0x32, 0x78, 0xa0, 0x3b, 0x65, 0x28, 0x4e, 0x1f, 0x99, 0x6a, 0x77, 0xdf, 0x48, 0x56, 0x3a, 0x70, + 0x8d, 0x3b, 0xb0, 0x82, 0x2e, 0x0d, 0xfd, 0x28, 0x87, 0xfe, 0xa2, 0xc0, 0x3b, 0xa5, 0xcd, 0x3b, + 0xfa, 0xa0, 0x0c, 0xc1, 0x69, 0x93, 0x41, 0xed, 0x3b, 0x6f, 0x20, 0x29, 0x91, 0x37, 0x38, 0xf2, + 0x0d, 0xb4, 0xa6, 0x8d, 0xf4, 0x21, 0x0e, 0x79, 0x30, 0x93, 0x99, 0xaf, 0xd0, 0x8d, 0x32, 0xdb, + 0x45, 0x13, 0x5e, 0xed, 0xe6, 0x88, 0xdc, 0x12, 0x5d, 0x05, 0xfd, 0x56, 0x81, 0xd9, 0xec, 0x24, + 0x81, 0x4a, 0x75, 0x14, 0xce, 0x23, 0xb5, 0xc6, 0xa8, 0xec, 0xd2, 0xe6, 0x0d, 0x7e, 0x22, 0x6b, + 0xe8, 0x6a, 0xc1, 0x89, 0xe4, 0x26, 0x17, 0xf4, 0x95, 0x02, 0x93, 0x49, 0x9b, 0x8f, 0xd6, 0x4b, + 0xe3, 0x90, 0x9d, 0x60, 0xca, 0x9f, 0xcc, 0xc1, 0x21, 0x45, 0xbd, 0xcd, 0xd1, 0x34, 0xd0, 0x8d, + 0xa2, 0xf8, 0x48, 0x66, 0xed, 0x39, 0x9f, 0x80, 0x5e, 0x68, 0xcf, 0xc5, 0xc8, 0xf3, 0x02, 0xfd, + 0x34, 0xa9, 0x43, 0x83, 0xdd, 0x32, 0xda, 0x1a, 0xb5, 0xf3, 0x4c, 0xa6, 0x89, 0xda, 0xad, 0xd7, + 0x90, 0x10, 0xa0, 0xb7, 0x94, 0x9d, 0xe6, 0xd7, 0x2f, 0xeb, 0xca, 0x37, 0x2f, 0xeb, 0xca, 0xbf, + 0x5f, 0xd6, 0x95, 0x5f, 0xbd, 0xaa, 0x57, 0xbe, 0x79, 0x55, 0xaf, 0xfc, 0xe3, 0x55, 0xbd, 0xf2, + 0xc3, 0xf7, 0x3b, 0x84, 0x1d, 0x44, 0xad, 0x86, 0x45, 0xdd, 0xac, 0x4b, 0xdd, 0xdb, 0x37, 0x79, + 0x9b, 0xa4, 0xf5, 0x28, 0xc7, 0xc2, 0x4d, 0x76, 0xe2, 0xe3, 0xb0, 0x75, 0x96, 0x93, 0xdf, 0xfb, + 0x36, 0x00, 0x00, 0xff, 0xff, 0x6a, 0xb8, 0x06, 0x80, 0x89, 0x17, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -2847,8 +2848,8 @@ func (m *ClobPairLeverageInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.Leverage != 0 { - i = encodeVarintQuery(dAtA, i, uint64(m.Leverage)) + if m.CustomImfPpm != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.CustomImfPpm)) i-- dAtA[i] = 0x10 } @@ -3630,8 +3631,8 @@ func (m *ClobPairLeverageInfo) Size() (n int) { if m.ClobPairId != 0 { n += 1 + sovQuery(uint64(m.ClobPairId)) } - if m.Leverage != 0 { - n += 1 + sovQuery(uint64(m.Leverage)) + if m.CustomImfPpm != 0 { + n += 1 + sovQuery(uint64(m.CustomImfPpm)) } return n } @@ -5490,9 +5491,9 @@ func (m *ClobPairLeverageInfo) Unmarshal(dAtA []byte) error { } case 2: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Leverage", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field CustomImfPpm", wireType) } - m.Leverage = 0 + m.CustomImfPpm = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowQuery @@ -5502,7 +5503,7 @@ func (m *ClobPairLeverageInfo) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.Leverage |= uint32(b&0x7F) << shift + m.CustomImfPpm |= uint32(b&0x7F) << shift if b < 0x80 { break } diff --git a/protocol/x/clob/types/tx.pb.go b/protocol/x/clob/types/tx.pb.go index 381c8a371e..23f9da0fe6 100644 --- a/protocol/x/clob/types/tx.pb.go +++ b/protocol/x/clob/types/tx.pb.go @@ -1095,8 +1095,8 @@ var xxx_messageInfo_MsgUpdateLiquidationsConfigResponse proto.InternalMessageInf type LeverageEntry struct { // The clob pair ID. ClobPairId uint32 `protobuf:"varint,1,opt,name=clob_pair_id,json=clobPairId,proto3" json:"clob_pair_id,omitempty"` - // The leverage amount. - Leverage uint32 `protobuf:"varint,2,opt,name=leverage,proto3" json:"leverage,omitempty"` + // The user selected imf. + CustomImfPpm uint32 `protobuf:"varint,2,opt,name=custom_imf_ppm,json=customImfPpm,proto3" json:"custom_imf_ppm,omitempty"` } func (m *LeverageEntry) Reset() { *m = LeverageEntry{} } @@ -1139,9 +1139,9 @@ func (m *LeverageEntry) GetClobPairId() uint32 { return 0 } -func (m *LeverageEntry) GetLeverage() uint32 { +func (m *LeverageEntry) GetCustomImfPpm() uint32 { if m != nil { - return m.Leverage + return m.CustomImfPpm } return 0 } @@ -1268,85 +1268,86 @@ func init() { func init() { proto.RegisterFile("dydxprotocol/clob/tx.proto", fileDescriptor_19b9e2c0de4ab64a) } var fileDescriptor_19b9e2c0de4ab64a = []byte{ - // 1236 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x58, 0xcf, 0x4f, 0x24, 0xc5, - 0x17, 0x9f, 0xde, 0xfd, 0x7e, 0x5d, 0xe6, 0xc1, 0xb0, 0x50, 0xcb, 0xca, 0x6c, 0x23, 0xc3, 0x30, - 0x02, 0x99, 0xd5, 0x65, 0x66, 0xc5, 0x0d, 0x9a, 0x35, 0xfe, 0x1a, 0xc2, 0x06, 0x22, 0x23, 0xd0, - 0x60, 0x62, 0xd4, 0xa4, 0xd3, 0xd3, 0x5d, 0x0c, 0x95, 0xed, 0xee, 0x1a, 0xba, 0x7b, 0x10, 0xae, - 0x9b, 0x78, 0xf7, 0x6e, 0x4c, 0xfc, 0x13, 0x3c, 0xec, 0xc1, 0xbb, 0x1e, 0xf6, 0xb8, 0xf1, 0xb4, - 0x89, 0x46, 0x0d, 0x1c, 0xfc, 0x37, 0x4c, 0x77, 0x75, 0xd7, 0x54, 0xd3, 0x3f, 0x18, 0xd1, 0x83, - 0x17, 0xe8, 0xaa, 0xfa, 0xbc, 0x5f, 0x9f, 0xf7, 0xea, 0xbd, 0xca, 0x80, 0x6c, 0x9c, 0x1a, 0x27, - 0x3d, 0x87, 0x7a, 0x54, 0xa7, 0x66, 0x53, 0x37, 0x69, 0xa7, 0xe9, 0x9d, 0x34, 0x82, 0x0d, 0x34, - 0x29, 0x9e, 0x35, 0xfc, 0x33, 0xf9, 0x8e, 0x4e, 0x5d, 0x8b, 0xba, 0x6a, 0xb0, 0xdb, 0x64, 0x0b, - 0x86, 0x96, 0xa7, 0xd9, 0xaa, 0x69, 0xb9, 0xdd, 0xe6, 0xf1, 0x1b, 0xfe, 0xbf, 0xf0, 0x60, 0xaa, - 0x4b, 0xbb, 0x94, 0x09, 0xf8, 0x5f, 0xe1, 0x6e, 0x33, 0x69, 0xb8, 0x63, 0x52, 0xfd, 0xb1, 0xea, - 0x68, 0x1e, 0x56, 0x4d, 0x62, 0x11, 0x4f, 0xd5, 0xa9, 0x7d, 0x40, 0x22, 0x35, 0xf3, 0x49, 0x01, - 0xff, 0x8f, 0xda, 0xd3, 0x88, 0x13, 0x42, 0xee, 0x27, 0x21, 0xf8, 0xa8, 0x4f, 0xbc, 0x53, 0xd5, - 0x23, 0xd8, 0x49, 0x53, 0x3a, 0x97, 0x94, 0xb0, 0x34, 0x4f, 0x3f, 0xc4, 0x51, 0x54, 0xb3, 0x49, - 0x00, 0x75, 0x0c, 0x1c, 0x59, 0x5c, 0xca, 0x38, 0x56, 0x1d, 0x6c, 0xd1, 0x63, 0xcd, 0x8c, 0xd4, - 0xbc, 0x9e, 0xc4, 0x99, 0xe4, 0xa8, 0x4f, 0x0c, 0xcd, 0x23, 0xd4, 0x76, 0xe3, 0x4e, 0xdd, 0x8d, - 0x81, 0xdd, 0x7e, 0x47, 0xd3, 0x75, 0xda, 0xb7, 0x3d, 0x57, 0xf8, 0x66, 0xd0, 0xda, 0x37, 0x12, - 0x4c, 0xb6, 0xdd, 0xee, 0x9a, 0x83, 0x35, 0x0f, 0xaf, 0x99, 0xb4, 0xb3, 0xa3, 0x11, 0x07, 0xad, - 0x42, 0x51, 0xeb, 0x7b, 0x87, 0xd4, 0x21, 0xde, 0x69, 0x59, 0xaa, 0x4a, 0xf5, 0x62, 0xab, 0xfc, - 0xf3, 0xd3, 0xe5, 0xa9, 0x30, 0x5f, 0x1f, 0x1a, 0x86, 0x83, 0x5d, 0x77, 0xcf, 0x73, 0x88, 0xdd, - 0x55, 0x06, 0x50, 0xf4, 0x1e, 0x14, 0x39, 0xa5, 0xe5, 0x6b, 0x55, 0xa9, 0x3e, 0xba, 0x32, 0xd3, - 0x48, 0x14, 0x41, 0x23, 0xb2, 0xd3, 0xfa, 0xdf, 0xb3, 0xdf, 0xe6, 0x0a, 0xca, 0x88, 0x1e, 0xae, - 0x1f, 0x8e, 0x3f, 0xf9, 0xf3, 0xfb, 0xd7, 0x06, 0xfa, 0x6a, 0x33, 0x70, 0x27, 0xe1, 0x9c, 0x82, - 0xdd, 0x1e, 0xb5, 0x5d, 0x5c, 0x23, 0x70, 0xbb, 0xed, 0x76, 0x77, 0x1c, 0xda, 0xa3, 0x2e, 0x36, - 0xb6, 0x7b, 0xd8, 0x61, 0x5c, 0xa0, 0x1d, 0x98, 0xa0, 0x7c, 0xa5, 0x1e, 0xf5, 0x71, 0x1f, 0x97, - 0xa5, 0xea, 0xf5, 0xfa, 0xe8, 0xca, 0x5c, 0x8a, 0x33, 0x5c, 0x50, 0xd1, 0xbe, 0x0c, 0x1d, 0xba, - 0x39, 0x10, 0xdf, 0xf5, 0xa5, 0x6b, 0x73, 0x30, 0x9b, 0x6a, 0x8a, 0xfb, 0xb2, 0x0e, 0x25, 0x1f, - 0x60, 0x6a, 0x3a, 0xde, 0xf6, 0xd3, 0x87, 0x1e, 0xc0, 0xff, 0x83, 0x3c, 0x06, 0xec, 0x8d, 0xae, - 0x94, 0xd3, 0x0c, 0xfb, 0xe7, 0xa1, 0x45, 0x06, 0xae, 0x4d, 0xb3, 0x90, 0xb8, 0x1a, 0xae, 0xff, - 0x07, 0x09, 0xc6, 0x7d, 0x26, 0x34, 0x5b, 0xc7, 0x26, 0xb3, 0xf0, 0x0e, 0x8c, 0xb0, 0x4a, 0x21, - 0x46, 0x68, 0x44, 0xce, 0x32, 0xb2, 0x69, 0x84, 0x66, 0x6e, 0x50, 0xb6, 0x44, 0x4b, 0x30, 0xde, - 0xa5, 0xd4, 0x50, 0x3d, 0x62, 0xaa, 0xc1, 0xad, 0x09, 0xb2, 0x55, 0xda, 0x28, 0x28, 0x63, 0xfe, - 0xfe, 0x3e, 0x31, 0x5b, 0xfe, 0x2e, 0x6a, 0xc2, 0xad, 0x38, 0x4e, 0xf5, 0x88, 0x85, 0xcb, 0xd7, - 0xab, 0x52, 0xfd, 0xc6, 0x46, 0x41, 0x99, 0x10, 0xc1, 0xfb, 0xc4, 0xc2, 0xad, 0x09, 0x41, 0x31, - 0xb5, 0x31, 0x3d, 0xa8, 0x95, 0xe1, 0xe5, 0xb8, 0xe7, 0x3c, 0xa8, 0x5f, 0x59, 0x50, 0x2d, 0xff, - 0xbe, 0xb0, 0x73, 0xb4, 0x0b, 0xa5, 0x41, 0x89, 0x0e, 0x22, 0x5b, 0x8a, 0x47, 0x26, 0x54, 0x74, - 0x63, 0x8f, 0x7f, 0xf3, 0x28, 0xc7, 0x5c, 0x61, 0x0f, 0xed, 0x02, 0x72, 0x0f, 0xa9, 0xe3, 0xa9, - 0x1e, 0x76, 0x2c, 0x55, 0x0f, 0xec, 0xb8, 0xe5, 0x6b, 0x41, 0x3d, 0xcc, 0x66, 0xa6, 0xc5, 0xf7, - 0x29, 0x54, 0x37, 0x11, 0x88, 0xef, 0x63, 0xc7, 0x62, 0x4e, 0xba, 0x68, 0x21, 0xc1, 0x9e, 0x4f, - 0x48, 0x29, 0xce, 0x5d, 0xad, 0x0d, 0x30, 0xd0, 0x85, 0xaa, 0x30, 0xc6, 0xaf, 0x46, 0x14, 0x58, - 0x49, 0x81, 0xa8, 0xf4, 0x37, 0x0d, 0x34, 0x0b, 0xa0, 0x9b, 0x04, 0x07, 0x71, 0x33, 0x07, 0x4b, - 0x4a, 0x91, 0xed, 0x6c, 0x1a, 0x6e, 0xed, 0xa9, 0x14, 0x10, 0x29, 0xb0, 0x15, 0x11, 0x89, 0xb6, - 0x61, 0x4a, 0x08, 0xd1, 0xed, 0xeb, 0x3a, 0xc6, 0x06, 0x36, 0xc2, 0xa2, 0xcf, 0x0f, 0x52, 0x41, - 0x3c, 0xbc, 0xbd, 0x48, 0x10, 0x6d, 0xc2, 0xa4, 0xa0, 0xf0, 0x40, 0x23, 0x26, 0x36, 0x86, 0xa2, - 0x4c, 0xb9, 0xc9, 0xb5, 0x3d, 0x0a, 0xa4, 0xa2, 0x06, 0xf3, 0x49, 0xcf, 0xf8, 0xef, 0x36, 0x98, - 0xb8, 0x73, 0xbc, 0x3e, 0x5f, 0x48, 0x30, 0x26, 0x76, 0x07, 0xff, 0x52, 0x07, 0xcd, 0x3d, 0xac, - 0xca, 0x57, 0x32, 0x2c, 0xb7, 0x7d, 0xcc, 0x46, 0x41, 0x61, 0x60, 0xf4, 0x2e, 0xc8, 0x02, 0x99, - 0xec, 0xce, 0xf6, 0xfc, 0x2b, 0x6e, 0x61, 0xdb, 0x0b, 0x82, 0x18, 0xdb, 0x28, 0x28, 0xd3, 0x9c, - 0xb8, 0x80, 0xcd, 0x9d, 0x08, 0x80, 0x1e, 0x41, 0x29, 0x36, 0x11, 0x82, 0x5a, 0xcb, 0x68, 0x65, - 0xec, 0x7a, 0x05, 0x30, 0xff, 0x2a, 0x53, 0x61, 0xdd, 0x1a, 0x85, 0x22, 0x6f, 0x6b, 0xb5, 0xdf, - 0x25, 0x58, 0xe4, 0x81, 0xaf, 0x07, 0x23, 0x6e, 0x9f, 0x60, 0x67, 0xcb, 0x1f, 0x70, 0x6b, 0xc1, - 0x28, 0xe9, 0x33, 0xe4, 0x95, 0x33, 0x65, 0x43, 0x39, 0x6b, 0x74, 0x86, 0x89, 0x6b, 0xa6, 0x44, - 0x90, 0xe7, 0x4a, 0x98, 0xcc, 0xdb, 0x38, 0x0d, 0x93, 0xc8, 0x6c, 0x13, 0x96, 0x87, 0x0a, 0x90, - 0x67, 0xfb, 0x17, 0x09, 0x16, 0xb8, 0x44, 0x70, 0x83, 0x15, 0xcd, 0xc3, 0xff, 0x22, 0x23, 0x8f, - 0x61, 0x3a, 0xe3, 0x81, 0x12, 0xa6, 0xb4, 0x91, 0x42, 0x48, 0x8e, 0x23, 0x21, 0x1f, 0x53, 0x9d, - 0x14, 0x48, 0x82, 0x8e, 0x06, 0xdc, 0x1b, 0x26, 0x38, 0xce, 0xc6, 0x8f, 0x12, 0xcc, 0x70, 0x81, - 0x2d, 0xe1, 0xa5, 0xc1, 0xe0, 0x57, 0x26, 0xe1, 0x0b, 0xb8, 0x95, 0xf2, 0x6e, 0x09, 0x2b, 0x62, - 0x31, 0x85, 0x80, 0xa4, 0xed, 0x30, 0x6e, 0x64, 0x26, 0x4e, 0x12, 0x51, 0x2f, 0xc2, 0xab, 0x39, - 0x41, 0xf0, 0x60, 0xdb, 0x50, 0xda, 0xc2, 0xc7, 0xd8, 0xd1, 0xba, 0x78, 0xdd, 0xf6, 0x9c, 0xd3, - 0x21, 0x9a, 0xb5, 0x0c, 0x23, 0x66, 0x28, 0xc2, 0x46, 0xa7, 0xc2, 0xd7, 0xb5, 0x9f, 0xc4, 0x96, - 0x17, 0x29, 0x46, 0x1f, 0xfd, 0xa3, 0xd1, 0x76, 0x61, 0xa8, 0x7d, 0x0c, 0x68, 0xe0, 0xa0, 0xe0, - 0x88, 0xdf, 0xa1, 0xab, 0x69, 0x2c, 0x8a, 0xe1, 0x29, 0x13, 0x51, 0x20, 0xd1, 0xf6, 0x43, 0xe4, - 0x13, 0x17, 0xf7, 0x2f, 0xd6, 0x1b, 0x23, 0x60, 0x44, 0xd9, 0xca, 0x57, 0x45, 0xb8, 0xde, 0x76, - 0xbb, 0xa8, 0x07, 0x28, 0xe5, 0x05, 0x56, 0x4f, 0x71, 0x21, 0xf5, 0x01, 0x25, 0xdf, 0x1f, 0x16, - 0xc9, 0x87, 0xdd, 0xa7, 0x00, 0xc2, 0x3b, 0xab, 0x9a, 0x21, 0xcf, 0x11, 0x72, 0xfd, 0x32, 0x04, - 0xd7, 0xfc, 0x39, 0x8c, 0x8a, 0x0f, 0xac, 0xf9, 0x74, 0x41, 0x01, 0x22, 0xdf, 0xbd, 0x14, 0x22, - 0x2a, 0x17, 0x1f, 0x3a, 0x19, 0xca, 0x05, 0x48, 0x96, 0xf2, 0xb4, 0x07, 0x80, 0x01, 0xe3, 0x17, - 0x5e, 0xf0, 0x0b, 0x19, 0x9e, 0xc5, 0x50, 0xf2, 0xbd, 0x61, 0x50, 0xa2, 0x95, 0x0b, 0x63, 0x3c, - 0xc3, 0x4a, 0x1c, 0x95, 0x65, 0x25, 0x7d, 0xea, 0xa2, 0xef, 0x24, 0xa8, 0x0d, 0x31, 0x97, 0xde, - 0xce, 0x53, 0x9a, 0x27, 0x29, 0x7f, 0x70, 0x55, 0x49, 0xee, 0xe2, 0xb7, 0x12, 0xcc, 0x5f, 0x3e, - 0x27, 0xde, 0xca, 0xb3, 0x93, 0x23, 0x28, 0xbf, 0x7f, 0x45, 0x41, 0xee, 0xdf, 0x13, 0x09, 0xca, - 0x99, 0x9d, 0xbb, 0x91, 0xa7, 0x3d, 0x89, 0x97, 0x57, 0xff, 0x1e, 0x3e, 0x59, 0x2d, 0xbc, 0x03, - 0xe6, 0x56, 0x4b, 0x84, 0xca, 0xaf, 0x96, 0x8b, 0x7d, 0xa8, 0xb5, 0xf3, 0xec, 0xac, 0x22, 0x3d, - 0x3f, 0xab, 0x48, 0x7f, 0x9c, 0x55, 0xa4, 0xaf, 0xcf, 0x2b, 0x85, 0xe7, 0xe7, 0x95, 0xc2, 0x8b, - 0xf3, 0x4a, 0xe1, 0xb3, 0xd5, 0x2e, 0xf1, 0x0e, 0xfb, 0x9d, 0x86, 0x4e, 0xad, 0xf8, 0x4f, 0x05, - 0xc7, 0x0f, 0x96, 0xf5, 0x43, 0x8d, 0xd8, 0x4d, 0xbe, 0x73, 0x12, 0xfe, 0x6e, 0x71, 0xda, 0xc3, - 0x6e, 0xe7, 0xa5, 0x60, 0xfb, 0xcd, 0xbf, 0x02, 0x00, 0x00, 0xff, 0xff, 0x95, 0x60, 0xb5, 0xd0, - 0xd9, 0x10, 0x00, 0x00, + // 1250 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x58, 0xcd, 0x6f, 0x1b, 0x45, + 0x14, 0xf7, 0xb6, 0x40, 0xeb, 0x17, 0x3b, 0x4d, 0xa7, 0x29, 0x71, 0xb7, 0xc4, 0x71, 0x4c, 0x12, + 0xb9, 0xd0, 0xd8, 0x25, 0x54, 0x01, 0x15, 0xf1, 0xe5, 0x28, 0x55, 0x22, 0x12, 0xe2, 0x6c, 0x82, + 0x40, 0x80, 0xb4, 0x5a, 0xef, 0x4e, 0x9c, 0x51, 0x77, 0x3d, 0x9b, 0xdd, 0x75, 0x48, 0xae, 0x95, + 0xb8, 0x73, 0x47, 0x48, 0xfc, 0x09, 0x1c, 0x7a, 0xe0, 0x0e, 0x87, 0x1e, 0x2b, 0x4e, 0x95, 0x40, + 0x80, 0x92, 0x03, 0xff, 0x06, 0xda, 0x9d, 0xdd, 0xf1, 0x6c, 0xf6, 0x23, 0x26, 0x70, 0xe0, 0x92, + 0xec, 0xcc, 0xfc, 0xde, 0xd7, 0xef, 0xbd, 0x79, 0x6f, 0x64, 0x90, 0x8d, 0x63, 0xe3, 0xc8, 0x76, + 0xa8, 0x47, 0x75, 0x6a, 0xb6, 0x74, 0x93, 0x76, 0x5b, 0xde, 0x51, 0x33, 0xd8, 0x40, 0xd7, 0xc5, + 0xb3, 0xa6, 0x7f, 0x26, 0xdf, 0xd2, 0xa9, 0x6b, 0x51, 0x57, 0x0d, 0x76, 0x5b, 0x6c, 0xc1, 0xd0, + 0xf2, 0x14, 0x5b, 0xb5, 0x2c, 0xb7, 0xd7, 0x3a, 0x7c, 0xc3, 0xff, 0x17, 0x1e, 0x4c, 0xf6, 0x68, + 0x8f, 0x32, 0x01, 0xff, 0x2b, 0xdc, 0x6d, 0x25, 0x0d, 0x77, 0x4d, 0xaa, 0x3f, 0x52, 0x1d, 0xcd, + 0xc3, 0xaa, 0x49, 0x2c, 0xe2, 0xa9, 0x3a, 0xed, 0xef, 0x91, 0x48, 0xcd, 0x6c, 0x52, 0xc0, 0xff, + 0xa3, 0xda, 0x1a, 0x71, 0x42, 0xc8, 0xbd, 0x24, 0x04, 0x1f, 0x0c, 0x88, 0x77, 0xac, 0x7a, 0x04, + 0x3b, 0x69, 0x4a, 0x67, 0x92, 0x12, 0x96, 0xe6, 0xe9, 0xfb, 0x38, 0x8a, 0x6a, 0x3a, 0x09, 0xa0, + 0x8e, 0x81, 0x23, 0x8b, 0x0b, 0x19, 0xc7, 0xaa, 0x83, 0x2d, 0x7a, 0xa8, 0x99, 0x91, 0x9a, 0xd7, + 0x93, 0x38, 0x93, 0x1c, 0x0c, 0x88, 0xa1, 0x79, 0x84, 0xf6, 0xdd, 0xb8, 0x53, 0x77, 0x62, 0x60, + 0x77, 0xd0, 0xd5, 0x74, 0x9d, 0x0e, 0xfa, 0x9e, 0x2b, 0x7c, 0x33, 0x68, 0xfd, 0x5b, 0x09, 0xae, + 0x6f, 0xba, 0xbd, 0x15, 0x07, 0x6b, 0x1e, 0x5e, 0x31, 0x69, 0xb7, 0xa3, 0x11, 0x07, 0x2d, 0x43, + 0x51, 0x1b, 0x78, 0xfb, 0xd4, 0x21, 0xde, 0x71, 0x45, 0xaa, 0x49, 0x8d, 0x62, 0xbb, 0xf2, 0xcb, + 0x93, 0xc5, 0xc9, 0x30, 0x5f, 0x1f, 0x1a, 0x86, 0x83, 0x5d, 0x77, 0xc7, 0x73, 0x48, 0xbf, 0xa7, + 0x0c, 0xa1, 0xe8, 0x3d, 0x28, 0x72, 0x4a, 0x2b, 0x97, 0x6a, 0x52, 0x63, 0x6c, 0xe9, 0x76, 0x33, + 0x51, 0x04, 0xcd, 0xc8, 0x4e, 0xfb, 0x85, 0xa7, 0xbf, 0xcf, 0x14, 0x94, 0xab, 0x7a, 0xb8, 0x7e, + 0x30, 0xfe, 0xf8, 0xaf, 0x1f, 0x5e, 0x1b, 0xea, 0xab, 0xdf, 0x86, 0x5b, 0x09, 0xe7, 0x14, 0xec, + 0xda, 0xb4, 0xef, 0xe2, 0x3a, 0x81, 0x9b, 0x9b, 0x6e, 0xaf, 0xe3, 0x50, 0x9b, 0xba, 0xd8, 0xd8, + 0xb2, 0xb1, 0xc3, 0xb8, 0x40, 0x1d, 0x98, 0xa0, 0x7c, 0xa5, 0x1e, 0x0c, 0xf0, 0x00, 0x57, 0xa4, + 0xda, 0xe5, 0xc6, 0xd8, 0xd2, 0x4c, 0x8a, 0x33, 0x5c, 0x50, 0xd1, 0xbe, 0x0a, 0x1d, 0xba, 0x36, + 0x14, 0xdf, 0xf6, 0xa5, 0xeb, 0x33, 0x30, 0x9d, 0x6a, 0x8a, 0xfb, 0xb2, 0x0a, 0x65, 0x1f, 0x60, + 0x6a, 0x3a, 0xde, 0xf2, 0xd3, 0x87, 0xee, 0xc3, 0x8b, 0x41, 0x1e, 0x03, 0xf6, 0xc6, 0x96, 0x2a, + 0x69, 0x86, 0xfd, 0xf3, 0xd0, 0x22, 0x03, 0xd7, 0xa7, 0x58, 0x48, 0x5c, 0x0d, 0xd7, 0xff, 0xa3, + 0x04, 0xe3, 0x3e, 0x13, 0x5a, 0x5f, 0xc7, 0x26, 0xb3, 0xf0, 0x0e, 0x5c, 0x65, 0x95, 0x42, 0x8c, + 0xd0, 0x88, 0x9c, 0x65, 0x64, 0xdd, 0x08, 0xcd, 0x5c, 0xa1, 0x6c, 0x89, 0x16, 0x60, 0xbc, 0x47, + 0xa9, 0xa1, 0x7a, 0xc4, 0x54, 0x83, 0x5b, 0x13, 0x64, 0xab, 0xbc, 0x56, 0x50, 0x4a, 0xfe, 0xfe, + 0x2e, 0x31, 0xdb, 0xfe, 0x2e, 0x6a, 0xc1, 0x8d, 0x38, 0x4e, 0xf5, 0x88, 0x85, 0x2b, 0x97, 0x6b, + 0x52, 0xe3, 0xca, 0x5a, 0x41, 0x99, 0x10, 0xc1, 0xbb, 0xc4, 0xc2, 0xed, 0x09, 0x41, 0x31, 0xed, + 0x63, 0xba, 0x57, 0xaf, 0xc0, 0xcb, 0x71, 0xcf, 0x79, 0x50, 0xbf, 0xb1, 0xa0, 0xda, 0xfe, 0x7d, + 0x61, 0xe7, 0x68, 0x1b, 0xca, 0xc3, 0x12, 0x1d, 0x46, 0xb6, 0x10, 0x8f, 0x4c, 0xa8, 0xe8, 0xe6, + 0x0e, 0xff, 0xe6, 0x51, 0x96, 0x5c, 0x61, 0x0f, 0x6d, 0x03, 0x72, 0xf7, 0xa9, 0xe3, 0xa9, 0x1e, + 0x76, 0x2c, 0x55, 0x0f, 0xec, 0xb8, 0x95, 0x4b, 0x41, 0x3d, 0x4c, 0x67, 0xa6, 0xc5, 0xf7, 0x29, + 0x54, 0x37, 0x11, 0x88, 0xef, 0x62, 0xc7, 0x62, 0x4e, 0xba, 0x68, 0x2e, 0xc1, 0x9e, 0x4f, 0x48, + 0x39, 0xce, 0x5d, 0x7d, 0x13, 0x60, 0xa8, 0x0b, 0xd5, 0xa0, 0xc4, 0xaf, 0x46, 0x14, 0x58, 0x59, + 0x81, 0xa8, 0xf4, 0xd7, 0x0d, 0x34, 0x0d, 0xa0, 0x9b, 0x04, 0x07, 0x71, 0x33, 0x07, 0xcb, 0x4a, + 0x91, 0xed, 0xac, 0x1b, 0x6e, 0xfd, 0x89, 0x14, 0x10, 0x29, 0xb0, 0x15, 0x11, 0x89, 0xb6, 0x60, + 0x52, 0x08, 0xd1, 0x1d, 0xe8, 0x3a, 0xc6, 0x06, 0x36, 0xc2, 0xa2, 0xcf, 0x0f, 0x52, 0x41, 0x3c, + 0xbc, 0x9d, 0x48, 0x10, 0xad, 0xc3, 0x75, 0x41, 0xe1, 0x9e, 0x46, 0x4c, 0x6c, 0x8c, 0x44, 0x99, + 0x72, 0x8d, 0x6b, 0x7b, 0x18, 0x48, 0x45, 0x0d, 0xe6, 0x13, 0xdb, 0xf8, 0xff, 0x36, 0x98, 0xb8, + 0x73, 0xbc, 0x3e, 0x9f, 0x4b, 0x50, 0x12, 0xbb, 0x83, 0x7f, 0xa9, 0x83, 0xe6, 0x1e, 0x56, 0xe5, + 0x2b, 0x19, 0x96, 0x37, 0x7d, 0xcc, 0x5a, 0x41, 0x61, 0x60, 0xf4, 0x2e, 0xc8, 0x02, 0x99, 0xec, + 0xce, 0xda, 0xfe, 0x15, 0xb7, 0x70, 0xdf, 0x0b, 0x82, 0x28, 0xad, 0x15, 0x94, 0x29, 0x4e, 0x5c, + 0xc0, 0x66, 0x27, 0x02, 0xa0, 0x87, 0x50, 0x8e, 0x4d, 0x84, 0xa0, 0xd6, 0x32, 0x5a, 0x19, 0xbb, + 0x5e, 0x01, 0xcc, 0xbf, 0xca, 0x54, 0x58, 0xb7, 0xc7, 0xa0, 0xc8, 0xdb, 0x5a, 0xfd, 0x0f, 0x09, + 0xe6, 0x79, 0xe0, 0xab, 0xc1, 0x88, 0xdb, 0x25, 0xd8, 0xd9, 0xf0, 0x07, 0xdc, 0x4a, 0x30, 0x4a, + 0x06, 0x0c, 0x79, 0xe1, 0x4c, 0xf5, 0xa1, 0x92, 0x35, 0x3a, 0xc3, 0xc4, 0xb5, 0x52, 0x22, 0xc8, + 0x73, 0x25, 0x4c, 0xe6, 0x4d, 0x9c, 0x86, 0x49, 0x64, 0xb6, 0x05, 0x8b, 0x23, 0x05, 0xc8, 0xb3, + 0xfd, 0xab, 0x04, 0x73, 0x5c, 0x22, 0xb8, 0xc1, 0x8a, 0xe6, 0xe1, 0xff, 0x90, 0x91, 0x47, 0x30, + 0x95, 0xf1, 0x40, 0x09, 0x53, 0xda, 0x4c, 0x21, 0x24, 0xc7, 0x91, 0x90, 0x8f, 0xc9, 0x6e, 0x0a, + 0x24, 0x41, 0x47, 0x13, 0xee, 0x8e, 0x12, 0x1c, 0x67, 0xe3, 0x27, 0x09, 0x6e, 0x73, 0x81, 0x0d, + 0xe1, 0xa5, 0xc1, 0xe0, 0x17, 0x26, 0xe1, 0x4b, 0xb8, 0x91, 0xf2, 0x6e, 0x09, 0x2b, 0x62, 0x3e, + 0x85, 0x80, 0xa4, 0xed, 0x30, 0x6e, 0x64, 0x26, 0x4e, 0x12, 0x51, 0xcf, 0xc3, 0xab, 0x39, 0x41, + 0xf0, 0x60, 0x3f, 0x85, 0xf2, 0x06, 0x3e, 0xc4, 0x8e, 0xd6, 0xc3, 0xab, 0x7d, 0xcf, 0x39, 0x1e, + 0xa1, 0x59, 0xcf, 0xc1, 0xb8, 0x3e, 0x70, 0x3d, 0x6a, 0xa9, 0xc4, 0xda, 0x53, 0x6d, 0xdb, 0x62, + 0x03, 0x54, 0x29, 0xb1, 0xdd, 0x75, 0x6b, 0xaf, 0x63, 0x5b, 0xf5, 0x9f, 0xc5, 0xe6, 0x17, 0x99, + 0x40, 0x1f, 0xfd, 0xab, 0x21, 0x77, 0x66, 0xbc, 0x7d, 0x0c, 0x68, 0xe8, 0xaa, 0x19, 0x9a, 0x08, + 0x7b, 0x75, 0x2d, 0x8d, 0x4f, 0x31, 0x50, 0x65, 0x22, 0x0a, 0x29, 0xda, 0x7e, 0x80, 0x7c, 0x0a, + 0xe3, 0xfe, 0xc5, 0xba, 0x64, 0x04, 0x8c, 0xc8, 0x5b, 0xfa, 0xba, 0x08, 0x97, 0x37, 0xdd, 0x1e, + 0xb2, 0x01, 0xa5, 0xbc, 0xc5, 0x1a, 0x29, 0x2e, 0xa4, 0x3e, 0xa5, 0xe4, 0x7b, 0xa3, 0x22, 0xf9, + 0xd8, 0xfb, 0x0c, 0x40, 0x78, 0x71, 0xd5, 0x32, 0xe4, 0x39, 0x42, 0x6e, 0x9c, 0x87, 0xe0, 0x9a, + 0xbf, 0x80, 0x31, 0xf1, 0xa9, 0x35, 0x9b, 0x2e, 0x28, 0x40, 0xe4, 0x3b, 0xe7, 0x42, 0x44, 0xe5, + 0xe2, 0x93, 0x27, 0x43, 0xb9, 0x00, 0xc9, 0x52, 0x9e, 0xf6, 0x14, 0x30, 0x60, 0xfc, 0xcc, 0x5b, + 0x7e, 0x2e, 0xc3, 0xb3, 0x18, 0x4a, 0xbe, 0x3b, 0x0a, 0x4a, 0xb4, 0x72, 0x66, 0xa0, 0x67, 0x58, + 0x89, 0xa3, 0xb2, 0xac, 0xa4, 0xcf, 0x5f, 0xf4, 0xbd, 0x04, 0xf5, 0x11, 0x26, 0xd4, 0xdb, 0x79, + 0x4a, 0xf3, 0x24, 0xe5, 0x0f, 0x2e, 0x2a, 0xc9, 0x5d, 0xfc, 0x4e, 0x82, 0xd9, 0xf3, 0x27, 0xc6, + 0x5b, 0x79, 0x76, 0x72, 0x04, 0xe5, 0xf7, 0x2f, 0x28, 0xc8, 0xfd, 0x7b, 0x2c, 0x41, 0x25, 0xb3, + 0x87, 0x37, 0xf3, 0xb4, 0x27, 0xf1, 0xf2, 0xf2, 0x3f, 0xc3, 0x27, 0xab, 0x85, 0x77, 0xc0, 0xdc, + 0x6a, 0x89, 0x50, 0xf9, 0xd5, 0x72, 0xb6, 0x0f, 0xb5, 0x3b, 0x4f, 0x4f, 0xaa, 0xd2, 0xb3, 0x93, + 0xaa, 0xf4, 0xe7, 0x49, 0x55, 0xfa, 0xe6, 0xb4, 0x5a, 0x78, 0x76, 0x5a, 0x2d, 0x3c, 0x3f, 0xad, + 0x16, 0x3e, 0x5f, 0xee, 0x11, 0x6f, 0x7f, 0xd0, 0x6d, 0xea, 0xd4, 0x8a, 0xff, 0x68, 0x70, 0x78, + 0x7f, 0x51, 0xdf, 0xd7, 0x48, 0xbf, 0xc5, 0x77, 0x8e, 0xc2, 0x5f, 0x30, 0x8e, 0x6d, 0xec, 0x76, + 0x5f, 0x0a, 0xb6, 0xdf, 0xfc, 0x3b, 0x00, 0x00, 0xff, 0xff, 0xcd, 0x24, 0x47, 0xbc, 0xe3, 0x10, + 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -2567,8 +2568,8 @@ func (m *LeverageEntry) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.Leverage != 0 { - i = encodeVarintTx(dAtA, i, uint64(m.Leverage)) + if m.CustomImfPpm != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.CustomImfPpm)) i-- dAtA[i] = 0x10 } @@ -2985,8 +2986,8 @@ func (m *LeverageEntry) Size() (n int) { if m.ClobPairId != 0 { n += 1 + sovTx(uint64(m.ClobPairId)) } - if m.Leverage != 0 { - n += 1 + sovTx(uint64(m.Leverage)) + if m.CustomImfPpm != 0 { + n += 1 + sovTx(uint64(m.CustomImfPpm)) } return n } @@ -4883,9 +4884,9 @@ func (m *LeverageEntry) Unmarshal(dAtA []byte) error { } case 2: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Leverage", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field CustomImfPpm", wireType) } - m.Leverage = 0 + m.CustomImfPpm = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -4895,7 +4896,7 @@ func (m *LeverageEntry) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.Leverage |= uint32(b&0x7F) << shift + m.CustomImfPpm |= uint32(b&0x7F) << shift if b < 0x80 { break } diff --git a/protocol/x/perpetuals/lib/lib.go b/protocol/x/perpetuals/lib/lib.go index 81b638c1f2..19d3200153 100644 --- a/protocol/x/perpetuals/lib/lib.go +++ b/protocol/x/perpetuals/lib/lib.go @@ -43,6 +43,7 @@ func GetPositionNetNotionalValueAndMarginRequirements( marketPrice pricestypes.MarketPrice, liquidityTier types.LiquidityTier, quantums *big.Int, + custom_imf_ppm uint32, ) ( risk margin.Risk, ) { @@ -56,6 +57,7 @@ func GetPositionNetNotionalValueAndMarginRequirements( marketPrice, liquidityTier, quantums, + custom_imf_ppm, ) return margin.Risk{ NC: nc, @@ -72,6 +74,7 @@ func GetNetCollateralAndMarginRequirements( liquidityTier types.LiquidityTier, quantums *big.Int, quoteBalance *big.Int, + custom_imf_ppm uint32, // 0 means use default liquidity tier margins ) ( risk margin.Risk, ) { @@ -80,6 +83,7 @@ func GetNetCollateralAndMarginRequirements( marketPrice, liquidityTier, quantums, + custom_imf_ppm, ) risk.NC.Add(risk.NC, quoteBalance) return risk @@ -109,11 +113,13 @@ func GetNetNotionalInQuoteQuantums( // GetMarginRequirementsInQuoteQuantums returns initial and maintenance margin requirements // in quote quantums, given the position size in base quantums. +// If leverage > 0, scales the margin requirements based on maxLeverage/userLeverage ratio. func GetMarginRequirementsInQuoteQuantums( perpetual types.Perpetual, marketPrice pricestypes.MarketPrice, liquidityTier types.LiquidityTier, bigQuantums *big.Int, + custom_imf_ppm uint32, // 0 means use default liquidity tier margins ) ( bigInitialMarginQuoteQuantums *big.Int, bigMaintenanceMarginQuoteQuantums *big.Int, @@ -140,6 +146,7 @@ func GetMarginRequirementsInQuoteQuantums( bigBaseInitialMarginQuoteQuantums := liquidityTier.GetInitialMarginQuoteQuantums( bigQuoteQuantums, big.NewInt(0), // pass in 0 as open interest to get base IMR. + big.NewInt(0), // pass in 0 to use the base IMR ) // Maintenance margin requirement quote quantums = IM in quote quantums * maintenance fraction PPM. bigMaintenanceMarginQuoteQuantums = lib.BigMulPpm( @@ -151,6 +158,8 @@ func GetMarginRequirementsInQuoteQuantums( bigInitialMarginQuoteQuantums = liquidityTier.GetInitialMarginQuoteQuantums( bigQuoteQuantums, openInterestQuoteQuantums, // pass in current OI to get scaled IMR. + lib.BigU(custom_imf_ppm), ) + return bigInitialMarginQuoteQuantums, bigMaintenanceMarginQuoteQuantums } diff --git a/protocol/x/perpetuals/lib/lib_test.go b/protocol/x/perpetuals/lib/lib_test.go index 2da3190acd..5bc6a52f8b 100644 --- a/protocol/x/perpetuals/lib/lib_test.go +++ b/protocol/x/perpetuals/lib/lib_test.go @@ -209,6 +209,7 @@ func TestGetNetCollateralAndMarginRequirements(t *testing.T) { test.marketPrice, test.liquidityTier, test.quantums, + 0, ) risk := lib.GetNetCollateralAndMarginRequirements( test.perpetual, @@ -216,6 +217,7 @@ func TestGetNetCollateralAndMarginRequirements(t *testing.T) { test.liquidityTier, test.quantums, test.quoteBalance, + 0, ) require.Equal(t, 0, new(big.Int).Add(enc, test.quoteBalance).Cmp(risk.NC)) require.Equal(t, eimr, risk.IMR) @@ -314,6 +316,7 @@ func BenchmarkGetMarginRequirementsInQuoteQuantums(b *testing.B) { marketPrice, liquidityTier, quantums, + 0, ) } } @@ -399,6 +402,7 @@ func TestGetMarginRequirementsInQuoteQuantums(t *testing.T) { test.marketPrice, test.liquidityTier, test.quantums, + 0, ) require.Equal(t, test.expectedImr, imr) require.Equal(t, test.expectedMmr, mmr) @@ -681,6 +685,7 @@ func TestGetMarginRequirementsInQuoteQuantums_2(t *testing.T) { marketPrice, liquidityTier, tc.bigBaseQuantums, + 0, ) require.Equal(t, tc.bigExpectedInitialMargin, imr, "Initial margin mismatch") diff --git a/protocol/x/perpetuals/types/liquidity_tier.go b/protocol/x/perpetuals/types/liquidity_tier.go index 543cf494f2..0b0697b55a 100644 --- a/protocol/x/perpetuals/types/liquidity_tier.go +++ b/protocol/x/perpetuals/types/liquidity_tier.go @@ -77,13 +77,14 @@ func (liquidityTier LiquidityTier) GetMaxAbsFundingClampPpm(clampFactorPpm uint3 func (liquidityTier LiquidityTier) GetInitialMarginQuoteQuantums( quoteQuantums *big.Int, oiQuoteQuantums *big.Int, + custom_imf_ppm *big.Int, ) *big.Int { totalImfPpm := liquidityTier.GetAdjustedInitialMarginPpm(oiQuoteQuantums) - return lib.BigMulPpm( - quoteQuantums, - totalImfPpm, - true, // Round up initial margin. - ) + if custom_imf_ppm.Sign() > 0 { + // use the configured IMF if it is greater than the OI scaled IMF + totalImfPpm = lib.BigMax(totalImfPpm, custom_imf_ppm) + } + return lib.BigMulPpm(quoteQuantums, totalImfPpm, true) // Round up initial margin. } // GetAdjustedInitialMarginPpm returns the adjusted initial margin (in ppm) based on the current open interest. diff --git a/protocol/x/perpetuals/types/liquidity_tier_test.go b/protocol/x/perpetuals/types/liquidity_tier_test.go index ccc196b67f..28b73ede54 100644 --- a/protocol/x/perpetuals/types/liquidity_tier_test.go +++ b/protocol/x/perpetuals/types/liquidity_tier_test.go @@ -235,9 +235,9 @@ func BenchmarkGetInitialMarginQuoteQuantums(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { - _ = liquidityTier.GetInitialMarginQuoteQuantums(bigQuoteQuantums, oiLower) - _ = liquidityTier.GetInitialMarginQuoteQuantums(bigQuoteQuantums, oiUpper) - _ = liquidityTier.GetInitialMarginQuoteQuantums(bigQuoteQuantums, oiMiddle) + _ = liquidityTier.GetInitialMarginQuoteQuantums(bigQuoteQuantums, oiLower, big.NewInt(0)) + _ = liquidityTier.GetInitialMarginQuoteQuantums(bigQuoteQuantums, oiUpper, big.NewInt(0)) + _ = liquidityTier.GetInitialMarginQuoteQuantums(bigQuoteQuantums, oiMiddle, big.NewInt(0)) } } @@ -357,7 +357,11 @@ func TestGetInitialMarginQuoteQuantums(t *testing.T) { if tc.openInterestNotional != nil { openInterestNotional.Set(tc.openInterestNotional) } - adjustedIMQuoteQuantums := liquidityTier.GetInitialMarginQuoteQuantums(tc.bigQuoteQuantums, openInterestNotional) + adjustedIMQuoteQuantums := liquidityTier.GetInitialMarginQuoteQuantums( + tc.bigQuoteQuantums, + openInterestNotional, + big.NewInt(0), // no leverage configured + ) require.Equal(t, tc.expectedInitialMarginQuoteQuantums, adjustedIMQuoteQuantums) }) diff --git a/protocol/x/subaccounts/keeper/leverage.go b/protocol/x/subaccounts/keeper/leverage.go new file mode 100644 index 0000000000..d0b172e7b6 --- /dev/null +++ b/protocol/x/subaccounts/keeper/leverage.go @@ -0,0 +1,128 @@ +package keeper + +import ( + errorsmod "cosmossdk.io/errors" + "cosmossdk.io/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/dydxprotocol/v4-chain/protocol/lib" + "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" +) + +// getLeverageStore returns a prefix store where leverage data is stored. +func (k Keeper) getLeverageStore(ctx sdk.Context) prefix.Store { + return prefix.NewStore(ctx.KVStore(k.storeKey), []byte(types.LeverageKeyPrefix)) +} + +// leverageKey returns the store key to retrieve leverage data for a subaccount. +func leverageKey(subaccountId *types.SubaccountId) []byte { + return subaccountId.ToStateKey() +} + +// SetLeverage stores leverage data for a subaccount. +func (k Keeper) SetLeverage(ctx sdk.Context, subaccountId *types.SubaccountId, leverageMap map[uint32]uint32) { + store := k.getLeverageStore(ctx) + key := leverageKey(subaccountId) + + var entries []*types.PerpetualLeverageEntry + sortedPerpIds := lib.GetSortedKeys[lib.Sortable[uint32]](leverageMap) + for _, perpetualId := range sortedPerpIds { + customImfPpm := leverageMap[perpetualId] + entries = append(entries, &types.PerpetualLeverageEntry{ + PerpetualId: perpetualId, + CustomImfPpm: customImfPpm, + }) + } + + leverageData := &types.LeverageData{ + Entries: entries, + } + + b := k.cdc.MustMarshal(leverageData) + store.Set(key, b) +} + +// GetLeverage retrieves leverage data for a subaccount. +func (k Keeper) GetLeverage(ctx sdk.Context, subaccountId *types.SubaccountId) (map[uint32]uint32, bool) { + store := k.getLeverageStore(ctx) + key := leverageKey(subaccountId) + + b := store.Get(key) + if b == nil { + return nil, false + } + + var leverageData types.LeverageData + k.cdc.MustUnmarshal(b, &leverageData) + + leverageMap := make(map[uint32]uint32) + for _, entry := range leverageData.Entries { + leverageMap[entry.PerpetualId] = entry.CustomImfPpm + } + + return leverageMap, true +} + +// UpdateLeverage updates leverage for specific perpetuals for a subaccount. +func (k Keeper) UpdateLeverage( + ctx sdk.Context, + subaccountId *types.SubaccountId, + perpetualLeverage map[uint32]uint32, +) error { + // Sort the perpetual IDs to ensure deterministic ordering + sortedPerpIds := lib.GetSortedKeys[lib.Sortable[uint32]](perpetualLeverage) + + // Validate leverage against maximum allowed leverage for each perpetual + for _, perpetualId := range sortedPerpIds { + custom_imf_ppm := perpetualLeverage[perpetualId] + minImfPpm, err := k.GetMinImfForPerpetual(ctx, perpetualId) + if err != nil { + return errorsmod.Wrapf( + types.ErrInvalidLeverage, + "failed to get max leverage for perpetual %d: %v", + perpetualId, + err, + ) + } + + if custom_imf_ppm < minImfPpm { + return errorsmod.Wrapf( + types.ErrLeverageExceedsMaximum, + "%d is less than minimum allowed imf (%d) for perpetual %d resulting in higher than allowed leverage", + custom_imf_ppm, + minImfPpm, + perpetualId, + ) + } + } + + // Get existing leverage data + existingLeverage, exists := k.GetLeverage(ctx, subaccountId) + if !exists { + existingLeverage = make(map[uint32]uint32) + } + + // Update with new leverage values + for perpetualId, custom_imf_ppm := range perpetualLeverage { + existingLeverage[perpetualId] = custom_imf_ppm + } + + // Store updated leverage + k.SetLeverage(ctx, subaccountId, existingLeverage) + return nil +} + +// GetMinImfForPerpetual returns the IMF ppm allowed for a perpetual +// based on its liquidity tier's initial margin requirement. +func (k Keeper) GetMinImfForPerpetual(ctx sdk.Context, perpetualId uint32) (uint32, error) { + // Get the perpetual and its liquidity tier in one call + _, _, liquidityTier, err := k.perpetualsKeeper.GetPerpetualAndMarketPriceAndLiquidityTier(ctx, perpetualId) + if err != nil { + return 0, err + } + + if liquidityTier.InitialMarginPpm == 0 { + return 0, types.ErrInitialMarginPpmIsZero + } + + return liquidityTier.InitialMarginPpm, nil +} diff --git a/protocol/x/subaccounts/keeper/margining.go b/protocol/x/subaccounts/keeper/margining.go index dacb3a1b59..517732f8dd 100644 --- a/protocol/x/subaccounts/keeper/margining.go +++ b/protocol/x/subaccounts/keeper/margining.go @@ -76,6 +76,7 @@ func getMarginedUpdate( perpInfo.LiquidityTier, pos.GetBigQuantums(), pos.GetQuoteBalance(), + 0, // Margining uses default leverage and MMR ) // case 2: the position is undercollateralized w.r.t. the maintenance margin requirement. @@ -171,6 +172,7 @@ func withdrawCollateralFromPerpetualPositions( perpInfo.LiquidityTier, pos.GetBigQuantums(), pos.GetQuoteBalance(), + 0, ) // Calculate the amount of extra collateral that can be withdrawn. diff --git a/protocol/x/subaccounts/keeper/subaccount.go b/protocol/x/subaccounts/keeper/subaccount.go index f195e2dbf3..397d33502d 100644 --- a/protocol/x/subaccounts/keeper/subaccount.go +++ b/protocol/x/subaccounts/keeper/subaccount.go @@ -251,6 +251,7 @@ func (k Keeper) getSettledUpdates( err error, ) { var idToSettledSubaccount = make(map[types.SubaccountId]types.Subaccount) + var idToLeverageMap = make(map[types.SubaccountId]map[uint32]uint32) settledUpdates = make([]types.SettledUpdate, len(updates)) subaccountIdToFundingPayments = make(map[types.SubaccountId]map[uint32]dtypes.SerializableInt) @@ -258,25 +259,41 @@ func (k Keeper) getSettledUpdates( for i, u := range updates { settledSubaccount, exists := idToSettledSubaccount[u.SubaccountId] var fundingPayments map[uint32]dtypes.SerializableInt + var leverageMap map[uint32]uint32 if exists && requireUniqueSubaccount { return nil, nil, types.ErrNonUniqueUpdatesSubaccount } - // Get and store the settledSubaccount if SubaccountId doesn't exist in - // idToSettledSubaccount map. + // Get and store the settledSubaccount and leverage if SubaccountId doesn't exist in maps. if !exists { subaccount := k.GetSubaccount(ctx, u.SubaccountId) settledSubaccount, fundingPayments = salib.GetSettledSubaccountWithPerpetuals(subaccount, perpInfos) + // Only fetch leverage if there are perpetual updates or perpetual positions + // to avoid unnecessary gas consumption + if len(u.PerpetualUpdates) > 0 || len(settledSubaccount.PerpetualPositions) > 0 { + if leverage, found := k.GetLeverage(ctx, &u.SubaccountId); found { + leverageMap = leverage + } + } + idToSettledSubaccount[u.SubaccountId] = settledSubaccount + idToLeverageMap[u.SubaccountId] = leverageMap subaccountIdToFundingPayments[u.SubaccountId] = fundingPayments + } else { + // Reuse cached leverage map if there are perpetual updates + // or perpetual positions + if len(u.PerpetualUpdates) > 0 || len(settledSubaccount.PerpetualPositions) > 0 { + leverageMap = idToLeverageMap[u.SubaccountId] + } } settledUpdate := types.SettledUpdate{ SettledSubaccount: settledSubaccount, AssetUpdates: u.AssetUpdates, PerpetualUpdates: u.PerpetualUpdates, + LeverageMap: leverageMap, } settledUpdates[i] = settledUpdate @@ -366,7 +383,7 @@ func (k Keeper) UpdateSubaccounts( return false, nil, err } - success, successPerUpdate, err = k.internalCanUpdateSubaccounts( + success, successPerUpdate, err = k.internalCanUpdateSubaccountsWithLeverage( ctx, settledUpdates, updateType, @@ -479,6 +496,9 @@ func (k Keeper) UpdateSubaccounts( // with the same `SubaccountId`, they are validated without respect to each // other. // +// This method automatically fetches leverage configuration for all subaccounts +// being updated and applies leverage-aware margin requirements. +// // Returns a `success` value of `true` if all updates are valid. // Returns a `successPerUpdates` value, which is a slice of `UpdateResult`. // These map to the updates and are used to indicate which of the updates @@ -511,23 +531,11 @@ func (k Keeper) CanUpdateSubaccounts( return false, nil, err } - success, successPerUpdate, err = k.internalCanUpdateSubaccounts(ctx, settledUpdates, updateType, perpInfos) + success, successPerUpdate, err = k.internalCanUpdateSubaccountsWithLeverage(ctx, settledUpdates, updateType, perpInfos) return success, successPerUpdate, err } -// internalCanUpdateSubaccounts will validate all `updates` to the relevant subaccounts and compute -// if any of the updates led to an isolated perpetual position being opened or closed. -// The `updates` do not have to contain `Subaccounts` with unique `SubaccountIds`. -// Each update is considered in isolation. Thus if two updates are provided -// with the same `Subaccount`, they are validated without respect to each -// other. -// The input subaccounts must be settled. -// -// Returns a `success` value of `true` if all updates are valid. -// Returns a `successPerUpdates` value, which is a slice of `UpdateResult`. -// These map to the updates and are used to indicate which of the updates -// caused a failure, if any. -func (k Keeper) internalCanUpdateSubaccounts( +func (k Keeper) internalCanUpdateSubaccountsWithLeverage( ctx sdk.Context, settledUpdates []types.SettledUpdate, updateType types.UpdateType, @@ -673,11 +681,7 @@ func (k Keeper) internalCanUpdateSubaccounts( } // Get the new collateralization and margin requirements with the update applied. - updatedSubaccount := salib.CalculateUpdatedSubaccount(u, perpInfos) - riskNew, err := salib.GetRiskForSubaccount( - updatedSubaccount, - perpInfos, - ) + riskNew, err := salib.GetRiskForSettledUpdate(u, perpInfos) if err != nil { return false, nil, err } @@ -699,6 +703,7 @@ func (k Keeper) internalCanUpdateSubaccounts( riskCurMap[saKey], err = salib.GetRiskForSubaccount( u.SettledSubaccount, perpInfos, + u.LeverageMap, ) if err != nil { return false, nil, err @@ -755,9 +760,16 @@ func (k Keeper) GetNetCollateralAndMarginRequirements( } updatedSubaccount := salib.CalculateUpdatedSubaccount(settledUpdate, perpInfos) + // Get leverage configuration for this subaccount + var leverageMap map[uint32]uint32 + if leverage, found := k.GetLeverage(ctx, &update.SubaccountId); found { + leverageMap = leverage + } + return salib.GetRiskForSubaccount( updatedSubaccount, perpInfos, + leverageMap, ) } diff --git a/protocol/x/subaccounts/lib/updates.go b/protocol/x/subaccounts/lib/updates.go index 672415cc27..3a30c2e0e4 100644 --- a/protocol/x/subaccounts/lib/updates.go +++ b/protocol/x/subaccounts/lib/updates.go @@ -343,6 +343,7 @@ func CalculateUpdatedSubaccount( func GetRiskForSubaccount( subaccount types.Subaccount, perpInfos perptypes.PerpInfos, + leverageMap map[uint32]uint32, // leverage per perpetual, nil means no leverage configured ) ( risk margin.Risk, err error, @@ -365,15 +366,37 @@ func GetRiskForSubaccount( // Iterate over all perpetuals and updates and calculate change to net collateral and margin requirements. for _, pos := range subaccount.PerpetualPositions { perpInfo := perpInfos.MustGet(pos.PerpetualId) + + // Get the configured imf for this perpetual (0 if not configured) + custom_imf_ppm := uint32(0) + if leverageMap != nil { + custom_imf_ppm = leverageMap[pos.PerpetualId] + } + r := perplib.GetNetCollateralAndMarginRequirements( perpInfo.Perpetual, perpInfo.Price, perpInfo.LiquidityTier, pos.GetBigQuantums(), pos.GetQuoteBalance(), + custom_imf_ppm, ) risk.AddInPlace(r) } return risk, nil } + +// GetRiskForSettledUpdate returns the risk value for a SettledUpdate with embedded leverage. +// This is a convenience function that extracts the leverage from the SettledUpdate and +// calls GetRiskForSubaccount with the updated subaccount. +func GetRiskForSettledUpdate( + settledUpdate types.SettledUpdate, + perpInfos perptypes.PerpInfos, +) ( + risk margin.Risk, + err error, +) { + updatedSubaccount := CalculateUpdatedSubaccount(settledUpdate, perpInfos) + return GetRiskForSubaccount(updatedSubaccount, perpInfos, settledUpdate.LeverageMap) +} diff --git a/protocol/x/subaccounts/lib/updates_test.go b/protocol/x/subaccounts/lib/updates_test.go index 4e75261c4b..250815a4b5 100644 --- a/protocol/x/subaccounts/lib/updates_test.go +++ b/protocol/x/subaccounts/lib/updates_test.go @@ -160,7 +160,7 @@ func TestGetRiskForSubaccount(t *testing.T) { } for name, tc := range tests { t.Run(name, func(t *testing.T) { - risk, err := lib.GetRiskForSubaccount(tc.subaccount, tc.perpInfos) + risk, err := lib.GetRiskForSubaccount(tc.subaccount, tc.perpInfos, nil) require.Equal(t, tc.expectedRisk, risk) if tc.expectedErr != nil { require.Equal(t, tc.expectedErr, err) @@ -183,6 +183,6 @@ func TestGetRiskForSubaccount_Panic(t *testing.T) { // Panics since relevant perpetual information cannot be found. require.Panics(t, func() { - _, _ = lib.GetRiskForSubaccount(subaccount, emptyPerpInfos) + _, _ = lib.GetRiskForSubaccount(subaccount, emptyPerpInfos, nil) }) } diff --git a/protocol/x/subaccounts/types/errors.go b/protocol/x/subaccounts/types/errors.go index 9650673ce0..5c0d938d20 100644 --- a/protocol/x/subaccounts/types/errors.go +++ b/protocol/x/subaccounts/types/errors.go @@ -78,4 +78,9 @@ var ( "subaccount not found at index in safety heap", ) ErrSafetyHeapSubaccountIndexNotFound = errorsmod.Register(ModuleName, 602, "subaccount index not found") + + // 700 - 799: leverage related. + ErrInvalidLeverage = errorsmod.Register(ModuleName, 700, "invalid leverage") + ErrLeverageExceedsMaximum = errorsmod.Register(ModuleName, 701, "leverage exceeds maximum allowed") + ErrInitialMarginPpmIsZero = errorsmod.Register(ModuleName, 702, "initial margin ppm cannot be zero") ) diff --git a/protocol/x/subaccounts/types/keys.go b/protocol/x/subaccounts/types/keys.go index f67d476082..921d1de5df 100644 --- a/protocol/x/subaccounts/types/keys.go +++ b/protocol/x/subaccounts/types/keys.go @@ -25,4 +25,7 @@ const ( SafetyHeapSubaccountIdsPrefix = "Heap/" SafetyHeapSubaccountToIndexPrefix = "Idx/" SafetyHeapLengthPrefix = "Len/" + + // Leverage + LeverageKeyPrefix = "Lev:" ) diff --git a/protocol/x/subaccounts/types/leverage.pb.go b/protocol/x/subaccounts/types/leverage.pb.go new file mode 100644 index 0000000000..a65dbe4dd5 --- /dev/null +++ b/protocol/x/subaccounts/types/leverage.pb.go @@ -0,0 +1,528 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: dydxprotocol/subaccounts/leverage.proto + +package types + +import ( + fmt "fmt" + proto "github.com/cosmos/gogoproto/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// PerpetualLeverageEntry represents a single perpetual leverage setting for +// internal storage +type PerpetualLeverageEntry struct { + // The perpetual ID (internal storage format) + PerpetualId uint32 `protobuf:"varint,1,opt,name=perpetual_id,json=perpetualId,proto3" json:"perpetual_id,omitempty"` + // The user selected IMF in parts per million + CustomImfPpm uint32 `protobuf:"varint,2,opt,name=custom_imf_ppm,json=customImfPpm,proto3" json:"custom_imf_ppm,omitempty"` +} + +func (m *PerpetualLeverageEntry) Reset() { *m = PerpetualLeverageEntry{} } +func (m *PerpetualLeverageEntry) String() string { return proto.CompactTextString(m) } +func (*PerpetualLeverageEntry) ProtoMessage() {} +func (*PerpetualLeverageEntry) Descriptor() ([]byte, []int) { + return fileDescriptor_78a5174593f1c911, []int{0} +} +func (m *PerpetualLeverageEntry) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PerpetualLeverageEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PerpetualLeverageEntry.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PerpetualLeverageEntry) XXX_Merge(src proto.Message) { + xxx_messageInfo_PerpetualLeverageEntry.Merge(m, src) +} +func (m *PerpetualLeverageEntry) XXX_Size() int { + return m.Size() +} +func (m *PerpetualLeverageEntry) XXX_DiscardUnknown() { + xxx_messageInfo_PerpetualLeverageEntry.DiscardUnknown(m) +} + +var xxx_messageInfo_PerpetualLeverageEntry proto.InternalMessageInfo + +func (m *PerpetualLeverageEntry) GetPerpetualId() uint32 { + if m != nil { + return m.PerpetualId + } + return 0 +} + +func (m *PerpetualLeverageEntry) GetCustomImfPpm() uint32 { + if m != nil { + return m.CustomImfPpm + } + return 0 +} + +// LeverageData represents the leverage settings for a subaccount +type LeverageData struct { + // List of leverage entries for this subaccount + Entries []*PerpetualLeverageEntry `protobuf:"bytes,1,rep,name=entries,proto3" json:"entries,omitempty"` +} + +func (m *LeverageData) Reset() { *m = LeverageData{} } +func (m *LeverageData) String() string { return proto.CompactTextString(m) } +func (*LeverageData) ProtoMessage() {} +func (*LeverageData) Descriptor() ([]byte, []int) { + return fileDescriptor_78a5174593f1c911, []int{1} +} +func (m *LeverageData) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *LeverageData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_LeverageData.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *LeverageData) XXX_Merge(src proto.Message) { + xxx_messageInfo_LeverageData.Merge(m, src) +} +func (m *LeverageData) XXX_Size() int { + return m.Size() +} +func (m *LeverageData) XXX_DiscardUnknown() { + xxx_messageInfo_LeverageData.DiscardUnknown(m) +} + +var xxx_messageInfo_LeverageData proto.InternalMessageInfo + +func (m *LeverageData) GetEntries() []*PerpetualLeverageEntry { + if m != nil { + return m.Entries + } + return nil +} + +func init() { + proto.RegisterType((*PerpetualLeverageEntry)(nil), "dydxprotocol.subaccounts.PerpetualLeverageEntry") + proto.RegisterType((*LeverageData)(nil), "dydxprotocol.subaccounts.LeverageData") +} + +func init() { + proto.RegisterFile("dydxprotocol/subaccounts/leverage.proto", fileDescriptor_78a5174593f1c911) +} + +var fileDescriptor_78a5174593f1c911 = []byte{ + // 249 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x4f, 0xa9, 0x4c, 0xa9, + 0x28, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0xce, 0xcf, 0xd1, 0x2f, 0x2e, 0x4d, 0x4a, 0x4c, 0x4e, 0xce, + 0x2f, 0xcd, 0x2b, 0x29, 0xd6, 0xcf, 0x49, 0x2d, 0x4b, 0x2d, 0x4a, 0x4c, 0x4f, 0xd5, 0x03, 0xcb, + 0x0a, 0x49, 0x20, 0x2b, 0xd4, 0x43, 0x52, 0xa8, 0x94, 0xc8, 0x25, 0x16, 0x90, 0x5a, 0x54, 0x90, + 0x5a, 0x52, 0x9a, 0x98, 0xe3, 0x03, 0xd5, 0xe4, 0x9a, 0x57, 0x52, 0x54, 0x29, 0xa4, 0xc8, 0xc5, + 0x53, 0x00, 0x93, 0x89, 0xcf, 0x4c, 0x91, 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x0d, 0xe2, 0x86, 0x8b, + 0x79, 0xa6, 0x08, 0xa9, 0x70, 0xf1, 0x25, 0x97, 0x16, 0x97, 0xe4, 0xe7, 0xc6, 0x67, 0xe6, 0xa6, + 0xc5, 0x17, 0x14, 0xe4, 0x4a, 0x30, 0x81, 0x15, 0xf1, 0x40, 0x44, 0x3d, 0x73, 0xd3, 0x02, 0x0a, + 0x72, 0x95, 0xa2, 0xb8, 0x78, 0x60, 0x26, 0xbb, 0x24, 0x96, 0x24, 0x0a, 0x79, 0x71, 0xb1, 0xa7, + 0xe6, 0x95, 0x14, 0x65, 0xa6, 0x16, 0x4b, 0x30, 0x2a, 0x30, 0x6b, 0x70, 0x1b, 0x19, 0xe8, 0xe1, + 0x72, 0x9e, 0x1e, 0x76, 0xb7, 0x05, 0xc1, 0x0c, 0x70, 0x0a, 0x3f, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, + 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4, 0x18, 0x27, 0x3c, 0x96, 0x63, 0xb8, 0xf0, 0x58, 0x8e, 0xe1, + 0xc6, 0x63, 0x39, 0x86, 0x28, 0xdb, 0xf4, 0xcc, 0x92, 0x8c, 0xd2, 0x24, 0xbd, 0xe4, 0xfc, 0x5c, + 0x7d, 0x94, 0x60, 0x2a, 0x33, 0xd1, 0x4d, 0xce, 0x48, 0xcc, 0xcc, 0xd3, 0x87, 0x8b, 0x54, 0xa0, + 0x04, 0x5d, 0x49, 0x65, 0x41, 0x6a, 0x71, 0x12, 0x1b, 0x58, 0xd6, 0x18, 0x10, 0x00, 0x00, 0xff, + 0xff, 0x83, 0xd3, 0xb1, 0xbe, 0x63, 0x01, 0x00, 0x00, +} + +func (m *PerpetualLeverageEntry) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PerpetualLeverageEntry) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PerpetualLeverageEntry) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.CustomImfPpm != 0 { + i = encodeVarintLeverage(dAtA, i, uint64(m.CustomImfPpm)) + i-- + dAtA[i] = 0x10 + } + if m.PerpetualId != 0 { + i = encodeVarintLeverage(dAtA, i, uint64(m.PerpetualId)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *LeverageData) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *LeverageData) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *LeverageData) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Entries) > 0 { + for iNdEx := len(m.Entries) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Entries[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintLeverage(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintLeverage(dAtA []byte, offset int, v uint64) int { + offset -= sovLeverage(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *PerpetualLeverageEntry) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PerpetualId != 0 { + n += 1 + sovLeverage(uint64(m.PerpetualId)) + } + if m.CustomImfPpm != 0 { + n += 1 + sovLeverage(uint64(m.CustomImfPpm)) + } + return n +} + +func (m *LeverageData) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Entries) > 0 { + for _, e := range m.Entries { + l = e.Size() + n += 1 + l + sovLeverage(uint64(l)) + } + } + return n +} + +func sovLeverage(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozLeverage(x uint64) (n int) { + return sovLeverage(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *PerpetualLeverageEntry) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLeverage + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PerpetualLeverageEntry: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PerpetualLeverageEntry: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PerpetualId", wireType) + } + m.PerpetualId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLeverage + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PerpetualId |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CustomImfPpm", wireType) + } + m.CustomImfPpm = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLeverage + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CustomImfPpm |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipLeverage(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthLeverage + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *LeverageData) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLeverage + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: LeverageData: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: LeverageData: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Entries", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLeverage + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthLeverage + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthLeverage + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Entries = append(m.Entries, &PerpetualLeverageEntry{}) + if err := m.Entries[len(m.Entries)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipLeverage(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthLeverage + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipLeverage(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowLeverage + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowLeverage + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowLeverage + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthLeverage + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupLeverage + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthLeverage + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthLeverage = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowLeverage = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupLeverage = fmt.Errorf("proto: unexpected end of group") +) diff --git a/protocol/x/subaccounts/types/settled_update.go b/protocol/x/subaccounts/types/settled_update.go index d41b5bffef..e60a185b4c 100644 --- a/protocol/x/subaccounts/types/settled_update.go +++ b/protocol/x/subaccounts/types/settled_update.go @@ -11,6 +11,9 @@ type SettledUpdate struct { AssetUpdates []AssetUpdate // A list of changes to make to any `PerpetualPositions` in the `Subaccount`. PerpetualUpdates []PerpetualUpdate + // Leverage configuration for this subaccount (perpetualId -> custom imf). + // nil means no leverage configured (use default margin requirements). + LeverageMap map[uint32]uint32 } func (u *SettledUpdate) GetAssetUpdates() map[uint32]AssetUpdate {