diff --git a/indexer/packages/v4-protos/src/codegen/dydxprotocol/vault/tx.rpc.msg.ts b/indexer/packages/v4-protos/src/codegen/dydxprotocol/vault/tx.rpc.msg.ts index a2eeb007602..1cbc3081b8e 100644 --- a/indexer/packages/v4-protos/src/codegen/dydxprotocol/vault/tx.rpc.msg.ts +++ b/indexer/packages/v4-protos/src/codegen/dydxprotocol/vault/tx.rpc.msg.ts @@ -1,11 +1,14 @@ import { Rpc } from "../../helpers"; import * as _m0 from "protobufjs/minimal"; -import { MsgDepositToMegavault, MsgDepositToMegavaultResponse, MsgUpdateDefaultQuotingParams, MsgUpdateDefaultQuotingParamsResponse, MsgUpdateOperatorParams, MsgUpdateOperatorParamsResponse, MsgSetVaultParams, MsgSetVaultParamsResponse, MsgUnlockShares, MsgUnlockSharesResponse, MsgAllocateToVault, MsgAllocateToVaultResponse } from "./tx"; +import { MsgDepositToMegavault, MsgDepositToMegavaultResponse, MsgWithdrawFromMegavault, MsgWithdrawFromMegavaultResponse, MsgUpdateDefaultQuotingParams, MsgUpdateDefaultQuotingParamsResponse, MsgUpdateOperatorParams, MsgUpdateOperatorParamsResponse, MsgSetVaultParams, MsgSetVaultParamsResponse, MsgUnlockShares, MsgUnlockSharesResponse, MsgAllocateToVault, MsgAllocateToVaultResponse } from "./tx"; /** Msg defines the Msg service. */ export interface Msg { /** DepositToMegavault deposits funds into megavault. */ depositToMegavault(request: MsgDepositToMegavault): Promise; + /** WithdrawFromMegavault withdraws shares from megavault. */ + + withdrawFromMegavault(request: MsgWithdrawFromMegavault): Promise; /** UpdateDefaultQuotingParams updates the default quoting params in state. */ updateDefaultQuotingParams(request: MsgUpdateDefaultQuotingParams): Promise; @@ -31,6 +34,7 @@ export class MsgClientImpl implements Msg { constructor(rpc: Rpc) { this.rpc = rpc; this.depositToMegavault = this.depositToMegavault.bind(this); + this.withdrawFromMegavault = this.withdrawFromMegavault.bind(this); this.updateDefaultQuotingParams = this.updateDefaultQuotingParams.bind(this); this.updateOperatorParams = this.updateOperatorParams.bind(this); this.setVaultParams = this.setVaultParams.bind(this); @@ -44,6 +48,12 @@ export class MsgClientImpl implements Msg { return promise.then(data => MsgDepositToMegavaultResponse.decode(new _m0.Reader(data))); } + withdrawFromMegavault(request: MsgWithdrawFromMegavault): Promise { + const data = MsgWithdrawFromMegavault.encode(request).finish(); + const promise = this.rpc.request("dydxprotocol.vault.Msg", "WithdrawFromMegavault", data); + return promise.then(data => MsgWithdrawFromMegavaultResponse.decode(new _m0.Reader(data))); + } + updateDefaultQuotingParams(request: MsgUpdateDefaultQuotingParams): Promise { const data = MsgUpdateDefaultQuotingParams.encode(request).finish(); const promise = this.rpc.request("dydxprotocol.vault.Msg", "UpdateDefaultQuotingParams", data); diff --git a/indexer/packages/v4-protos/src/codegen/dydxprotocol/vault/tx.ts b/indexer/packages/v4-protos/src/codegen/dydxprotocol/vault/tx.ts index 4f749db8a7f..8dcbf656a79 100644 --- a/indexer/packages/v4-protos/src/codegen/dydxprotocol/vault/tx.ts +++ b/indexer/packages/v4-protos/src/codegen/dydxprotocol/vault/tx.ts @@ -1,7 +1,7 @@ import { SubaccountId, SubaccountIdSDKType } from "../subaccounts/subaccount"; +import { NumShares, NumSharesSDKType } from "./share"; import { QuotingParams, QuotingParamsSDKType, OperatorParams, OperatorParamsSDKType, VaultParams, VaultParamsSDKType, Params, ParamsSDKType } from "./params"; import { VaultId, VaultIdSDKType } from "./vault"; -import { NumShares, NumSharesSDKType } from "./share"; import * as _m0 from "protobufjs/minimal"; import { DeepPartial } from "../../helpers"; /** @@ -40,6 +40,60 @@ export interface MsgDepositToMegavaultResponseSDKType { /** The number of shares minted from the deposit. */ minted_shares?: NumSharesSDKType; } +/** + * MsgWithdrawFromMegavault withdraws the specified shares from megavault to + * a subaccount. + */ + +export interface MsgWithdrawFromMegavault { + /** The subaccount to withdraw to. */ + subaccountId?: SubaccountId; + /** Number of shares to withdraw. */ + + shares?: NumShares; + /** + * The minimum number of quote quantums above shares should redeem, i.e. + * transaction fails if above shares redeem less than min_quote_quantums. + */ + + minQuoteQuantums: Uint8Array; +} +/** + * MsgWithdrawFromMegavault withdraws the specified shares from megavault to + * a subaccount. + */ + +export interface MsgWithdrawFromMegavaultSDKType { + /** The subaccount to withdraw to. */ + subaccount_id?: SubaccountIdSDKType; + /** Number of shares to withdraw. */ + + shares?: NumSharesSDKType; + /** + * The minimum number of quote quantums above shares should redeem, i.e. + * transaction fails if above shares redeem less than min_quote_quantums. + */ + + min_quote_quantums: Uint8Array; +} +/** + * MsgWithdrawFromMegavaultResponse is the Msg/WithdrawFromMegavault response + * type. + */ + +export interface MsgWithdrawFromMegavaultResponse { + /** The number of quote quantums redeemed from the withdrawal. */ + quoteQuantums: Uint8Array; +} +/** + * MsgWithdrawFromMegavaultResponse is the Msg/WithdrawFromMegavault response + * type. + */ + +export interface MsgWithdrawFromMegavaultResponseSDKType { + /** The number of quote quantums redeemed from the withdrawal. */ + quote_quantums: Uint8Array; +} /** * MsgUpdateDefaultQuotingParams is the Msg/UpdateDefaultQuotingParams request * type. @@ -307,6 +361,116 @@ export const MsgDepositToMegavaultResponse = { }; +function createBaseMsgWithdrawFromMegavault(): MsgWithdrawFromMegavault { + return { + subaccountId: undefined, + shares: undefined, + minQuoteQuantums: new Uint8Array() + }; +} + +export const MsgWithdrawFromMegavault = { + encode(message: MsgWithdrawFromMegavault, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.subaccountId !== undefined) { + SubaccountId.encode(message.subaccountId, writer.uint32(10).fork()).ldelim(); + } + + if (message.shares !== undefined) { + NumShares.encode(message.shares, writer.uint32(18).fork()).ldelim(); + } + + if (message.minQuoteQuantums.length !== 0) { + writer.uint32(26).bytes(message.minQuoteQuantums); + } + + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): MsgWithdrawFromMegavault { + const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseMsgWithdrawFromMegavault(); + + while (reader.pos < end) { + const tag = reader.uint32(); + + switch (tag >>> 3) { + case 1: + message.subaccountId = SubaccountId.decode(reader, reader.uint32()); + break; + + case 2: + message.shares = NumShares.decode(reader, reader.uint32()); + break; + + case 3: + message.minQuoteQuantums = reader.bytes(); + break; + + default: + reader.skipType(tag & 7); + break; + } + } + + return message; + }, + + fromPartial(object: DeepPartial): MsgWithdrawFromMegavault { + const message = createBaseMsgWithdrawFromMegavault(); + message.subaccountId = object.subaccountId !== undefined && object.subaccountId !== null ? SubaccountId.fromPartial(object.subaccountId) : undefined; + message.shares = object.shares !== undefined && object.shares !== null ? NumShares.fromPartial(object.shares) : undefined; + message.minQuoteQuantums = object.minQuoteQuantums ?? new Uint8Array(); + return message; + } + +}; + +function createBaseMsgWithdrawFromMegavaultResponse(): MsgWithdrawFromMegavaultResponse { + return { + quoteQuantums: new Uint8Array() + }; +} + +export const MsgWithdrawFromMegavaultResponse = { + encode(message: MsgWithdrawFromMegavaultResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.quoteQuantums.length !== 0) { + writer.uint32(10).bytes(message.quoteQuantums); + } + + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): MsgWithdrawFromMegavaultResponse { + const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseMsgWithdrawFromMegavaultResponse(); + + while (reader.pos < end) { + const tag = reader.uint32(); + + switch (tag >>> 3) { + case 1: + message.quoteQuantums = reader.bytes(); + break; + + default: + reader.skipType(tag & 7); + break; + } + } + + return message; + }, + + fromPartial(object: DeepPartial): MsgWithdrawFromMegavaultResponse { + const message = createBaseMsgWithdrawFromMegavaultResponse(); + message.quoteQuantums = object.quoteQuantums ?? new Uint8Array(); + return message; + } + +}; + function createBaseMsgUpdateDefaultQuotingParams(): MsgUpdateDefaultQuotingParams { return { authority: "", diff --git a/proto/dydxprotocol/vault/tx.proto b/proto/dydxprotocol/vault/tx.proto index 0ad8faa0731..ce0a0f519ff 100644 --- a/proto/dydxprotocol/vault/tx.proto +++ b/proto/dydxprotocol/vault/tx.proto @@ -17,6 +17,10 @@ service Msg { rpc DepositToMegavault(MsgDepositToMegavault) returns (MsgDepositToMegavaultResponse); + // WithdrawFromMegavault withdraws shares from megavault. + rpc WithdrawFromMegavault(MsgWithdrawFromMegavault) + returns (MsgWithdrawFromMegavaultResponse); + // UpdateDefaultQuotingParams updates the default quoting params in state. rpc UpdateDefaultQuotingParams(MsgUpdateDefaultQuotingParams) returns (MsgUpdateDefaultQuotingParamsResponse); @@ -61,6 +65,40 @@ message MsgDepositToMegavaultResponse { NumShares minted_shares = 1 [ (gogoproto.nullable) = false ]; } +// MsgWithdrawFromMegavault withdraws the specified shares from megavault to +// a subaccount. +message MsgWithdrawFromMegavault { + // This annotation enforces that the tx signer is the owner specified in + // `subaccount_id`. + option (cosmos.msg.v1.signer) = "subaccount_id"; + + // The subaccount to withdraw to. + dydxprotocol.subaccounts.SubaccountId subaccount_id = 1 + [ (gogoproto.nullable) = false ]; + + // Number of shares to withdraw. + NumShares shares = 2 [ (gogoproto.nullable) = false ]; + + // The minimum number of quote quantums above shares should redeem, i.e. + // transaction fails if above shares redeem less than min_quote_quantums. + bytes min_quote_quantums = 3 [ + (gogoproto.customtype) = + "github.com/dydxprotocol/v4-chain/protocol/dtypes.SerializableInt", + (gogoproto.nullable) = false + ]; +} + +// MsgWithdrawFromMegavaultResponse is the Msg/WithdrawFromMegavault response +// type. +message MsgWithdrawFromMegavaultResponse { + // The number of quote quantums redeemed from the withdrawal. + bytes quote_quantums = 1 [ + (gogoproto.customtype) = + "github.com/dydxprotocol/v4-chain/protocol/dtypes.SerializableInt", + (gogoproto.nullable) = false + ]; +} + // MsgUpdateDefaultQuotingParams is the Msg/UpdateDefaultQuotingParams request // type. message MsgUpdateDefaultQuotingParams { diff --git a/protocol/app/module/interface_registry.go b/protocol/app/module/interface_registry.go index 367e9c46466..f750cad6415 100644 --- a/protocol/app/module/interface_registry.go +++ b/protocol/app/module/interface_registry.go @@ -95,6 +95,9 @@ func NewInterfaceRegistry(addrPrefix string, valAddrPrefix string) (types.Interf "dydxprotocol.vault.MsgDepositToMegavault": getLegacyMsgSignerFn( []string{"subaccount_id", "owner"}, ), + "dydxprotocol.vault.MsgWithdrawFromMegavault": getLegacyMsgSignerFn( + []string{"subaccount_id", "owner"}, + ), "dydxprotocol.listing.MsgCreateMarketPermissionless": getLegacyMsgSignerFn( []string{"subaccount_id", "owner"}, ), diff --git a/protocol/app/msgs/all_msgs.go b/protocol/app/msgs/all_msgs.go index 0743ada9485..b3c8d375688 100644 --- a/protocol/app/msgs/all_msgs.go +++ b/protocol/app/msgs/all_msgs.go @@ -262,6 +262,8 @@ var ( "/dydxprotocol.vault.MsgUpdateOperatorParams": {}, "/dydxprotocol.vault.MsgUpdateOperatorParamsResponse": {}, "/dydxprotocol.vault.MsgUpdateParams": {}, + "/dydxprotocol.vault.MsgWithdrawFromMegavault": {}, + "/dydxprotocol.vault.MsgWithdrawFromMegavaultResponse": {}, // vest "/dydxprotocol.vest.MsgSetVestEntry": {}, diff --git a/protocol/app/msgs/normal_msgs.go b/protocol/app/msgs/normal_msgs.go index 5032a41961e..2e49450f3a3 100644 --- a/protocol/app/msgs/normal_msgs.go +++ b/protocol/app/msgs/normal_msgs.go @@ -246,12 +246,14 @@ var ( "/dydxprotocol.sending.MsgWithdrawFromSubaccountResponse": nil, // vault - "/dydxprotocol.vault.MsgAllocateToVault": &vault.MsgAllocateToVault{}, - "/dydxprotocol.vault.MsgAllocateToVaultResponse": nil, - "/dydxprotocol.vault.MsgDepositToMegavault": &vault.MsgDepositToMegavault{}, - "/dydxprotocol.vault.MsgDepositToMegavaultResponse": nil, - "/dydxprotocol.vault.MsgSetVaultParams": &vault.MsgSetVaultParams{}, - "/dydxprotocol.vault.MsgSetVaultParamsResponse": nil, + "/dydxprotocol.vault.MsgAllocateToVault": &vault.MsgAllocateToVault{}, + "/dydxprotocol.vault.MsgAllocateToVaultResponse": nil, + "/dydxprotocol.vault.MsgDepositToMegavault": &vault.MsgDepositToMegavault{}, + "/dydxprotocol.vault.MsgDepositToMegavaultResponse": nil, + "/dydxprotocol.vault.MsgSetVaultParams": &vault.MsgSetVaultParams{}, + "/dydxprotocol.vault.MsgSetVaultParamsResponse": nil, + "/dydxprotocol.vault.MsgWithdrawFromMegavault": &vault.MsgWithdrawFromMegavault{}, + "/dydxprotocol.vault.MsgWithdrawFromMegavaultResponse": nil, } NormalMsgsSlinky = map[string]sdk.Msg{ diff --git a/protocol/app/msgs/normal_msgs_test.go b/protocol/app/msgs/normal_msgs_test.go index f6bbdc68378..db7c4c7f093 100644 --- a/protocol/app/msgs/normal_msgs_test.go +++ b/protocol/app/msgs/normal_msgs_test.go @@ -153,6 +153,8 @@ func TestNormalMsgs_Key(t *testing.T) { "/dydxprotocol.vault.MsgDepositToMegavaultResponse", "/dydxprotocol.vault.MsgSetVaultParams", "/dydxprotocol.vault.MsgSetVaultParamsResponse", + "/dydxprotocol.vault.MsgWithdrawFromMegavault", + "/dydxprotocol.vault.MsgWithdrawFromMegavaultResponse", // ibc application module: ICA "/ibc.applications.interchain_accounts.v1.InterchainAccount", diff --git a/protocol/testutil/encoding/utils.go b/protocol/testutil/encoding/utils.go index 1bd3d73eed9..d337742ab71 100644 --- a/protocol/testutil/encoding/utils.go +++ b/protocol/testutil/encoding/utils.go @@ -93,6 +93,7 @@ func GetTestEncodingCfg() testutil.TestEncodingConfig { // Vault. &vaulttypes.MsgDepositToMegavault{}, + &vaulttypes.MsgWithdrawFromMegavault{}, } for _, msg := range msgInterfacesToRegister { diff --git a/protocol/x/vault/keeper/msg_server_withdraw_from_megavault.go b/protocol/x/vault/keeper/msg_server_withdraw_from_megavault.go new file mode 100644 index 00000000000..c9b1ff88e06 --- /dev/null +++ b/protocol/x/vault/keeper/msg_server_withdraw_from_megavault.go @@ -0,0 +1,31 @@ +package keeper + +import ( + "context" + + "github.com/dydxprotocol/v4-chain/protocol/dtypes" + "github.com/dydxprotocol/v4-chain/protocol/lib" + "github.com/dydxprotocol/v4-chain/protocol/x/vault/types" +) + +// WithdrawFromMegavault withdraws from megavault to a subaccount. +func (k msgServer) WithdrawFromMegavault( + goCtx context.Context, + msg *types.MsgWithdrawFromMegavault, +) (*types.MsgWithdrawFromMegavaultResponse, error) { + ctx := lib.UnwrapSDKContext(goCtx, types.ModuleName) + + redeemedQuoteQuantums, err := k.Keeper.WithdrawFromMegavault( + ctx, + msg.SubaccountId, + msg.Shares.NumShares.BigInt(), + msg.MinQuoteQuantums.BigInt(), + ) + if err != nil { + return nil, err + } + + return &types.MsgWithdrawFromMegavaultResponse{ + QuoteQuantums: dtypes.NewIntFromBigInt(redeemedQuoteQuantums), + }, nil +} diff --git a/protocol/x/vault/keeper/msg_server_withdraw_from_megavault_test.go b/protocol/x/vault/keeper/msg_server_withdraw_from_megavault_test.go new file mode 100644 index 00000000000..3b59602f8eb --- /dev/null +++ b/protocol/x/vault/keeper/msg_server_withdraw_from_megavault_test.go @@ -0,0 +1,512 @@ +package keeper_test + +import ( + "bytes" + "math/big" + "testing" + + abcitypes "github.com/cometbft/cometbft/abci/types" + "github.com/cometbft/cometbft/types" + sdktypes "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" + assetstypes "github.com/dydxprotocol/v4-chain/protocol/x/assets/types" + clobtypes "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" + perptypes "github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/types" + pricestypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" + satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" + vaulttypes "github.com/dydxprotocol/v4-chain/protocol/x/vault/types" + "github.com/stretchr/testify/require" +) + +type VaultSetup struct { + id vaulttypes.VaultId + params vaulttypes.VaultParams + assetQuoteQuantums *big.Int + positionBaseQuantums *big.Int + clobPair clobtypes.ClobPair + perpetual perptypes.Perpetual + marketParam pricestypes.MarketParam + marketPrice pricestypes.MarketPrice + postWithdrawalEquity *big.Int +} + +func TestMsgWithdrawFromMegavault(t *testing.T) { + tests := map[string]struct { + /* --- Setup --- */ + // Quote quantums that main vault has. + mainVaultBalance uint64 + // Total shares before withdrawal. + totalShares uint64 + // Owner address. + owner string + // Owner total shares. + ownerTotalShares uint64 + // Owner locked shares. + ownerLockedShares uint64 + // Vaults. + vaults []VaultSetup + // Shares to withdraw. + sharesToWithdraw uint64 + // Minimum quote quantums to redeem. + minQuoteQuantums uint64 + + /* --- Expectations --- */ + // Whether DeliverTx should fail. + deliverTxFails bool + // Quote quantums that should be redeemed. + redeemedQuoteQuantums uint64 + // Total shares after withdrawal. + expectedTotalShares uint64 + // Owner shares after withdrawal. + expectedOwnerShares uint64 + }{ + "Success: Withdraw some unlocked shares (5% of total), No sub-vaults, Redeemed quantums = Min quantums": { + mainVaultBalance: 100, + totalShares: 200, + owner: constants.AliceAccAddress.String(), + ownerTotalShares: 50, + ownerLockedShares: 25, + sharesToWithdraw: 10, + minQuoteQuantums: 5, + deliverTxFails: false, + redeemedQuoteQuantums: 5, // 5% of 100 + expectedTotalShares: 190, // 200 - 10 + expectedOwnerShares: 40, // 50 - 10 + }, + "Success: Withdraw all unlocked shares (8% of total), No sub-vaults, Redeemed quantums > Min quantums": { + mainVaultBalance: 1_234, + totalShares: 500, + owner: constants.BobAccAddress.String(), + ownerTotalShares: 47, + ownerLockedShares: 7, + sharesToWithdraw: 40, + minQuoteQuantums: 95, + deliverTxFails: false, + redeemedQuoteQuantums: 98, // 1234 * 0.08 = 98.72 ~= 98 (rounded down) + expectedTotalShares: 460, // 500 - 40 + expectedOwnerShares: 7, // 47 - 40 + }, + "Success: Withdraw all shares (100% of total), No sub-vaults, Redeemed quantums = Min quantums": { + mainVaultBalance: 654_321, + totalShares: 787_565, + owner: constants.CarlAccAddress.String(), + ownerTotalShares: 787_565, + ownerLockedShares: 0, + sharesToWithdraw: 787_565, + minQuoteQuantums: 654_321, + deliverTxFails: false, + redeemedQuoteQuantums: 654_321, // all main vault balance + expectedTotalShares: 0, + expectedOwnerShares: 0, + }, + "Failure: Withdraw some unlocked shares (8% of total), one sub-vault, Redeemed quantums < Min quantums": { + mainVaultBalance: 1_234, + totalShares: 500, + owner: constants.BobAccAddress.String(), + ownerTotalShares: 47, + ownerLockedShares: 7, + vaults: []VaultSetup{ + { + id: constants.Vault_Clob0, + params: vaulttypes.VaultParams{ + Status: vaulttypes.VaultStatus_VAULT_STATUS_DEACTIVATED, + }, + assetQuoteQuantums: big.NewInt(400), + positionBaseQuantums: big.NewInt(0), + clobPair: constants.ClobPair_Btc, + perpetual: constants.BtcUsd_20PercentInitial_10PercentMaintenance, + marketParam: constants.TestMarketParams[0], + marketPrice: constants.TestMarketPrices[0], + postWithdrawalEquity: big.NewInt(400), // unchanged + }, + }, + sharesToWithdraw: 40, + minQuoteQuantums: 131, // greater than redeemed quote quantums + deliverTxFails: true, + redeemedQuoteQuantums: 130, // 1234 * 0.08 + 400 * 0.08 = 130.72 ~= 130 (rounded down) + expectedTotalShares: 500, // unchanged + expectedOwnerShares: 47, // unchanged + }, + "Success: Withdraw some unlocked shares (0.4444% of total), 888_888 quantums in main vault, " + + "one quoting sub-vault with negative equity": { + mainVaultBalance: 888_888, + totalShares: 1_000_000, + owner: constants.AliceAccAddress.String(), + ownerTotalShares: 9999, + ownerLockedShares: 134, + vaults: []VaultSetup{ + { + id: constants.Vault_Clob0, + params: vaulttypes.VaultParams{ + Status: vaulttypes.VaultStatus_VAULT_STATUS_QUOTING, + }, + assetQuoteQuantums: big.NewInt(-345), + positionBaseQuantums: big.NewInt(0), + clobPair: constants.ClobPair_Btc, + perpetual: constants.BtcUsd_20PercentInitial_10PercentMaintenance, + marketParam: constants.TestMarketParams[0], + marketPrice: constants.TestMarketPrices[0], + postWithdrawalEquity: big.NewInt(-345), + }, + }, + sharesToWithdraw: 4444, + minQuoteQuantums: 0, + deliverTxFails: false, + redeemedQuoteQuantums: 3_950, // 888_888 * 4444 / 1_000_000 ~= 3950 (sub-vault is skipped) + expectedTotalShares: 995_556, // 1_000_000 - 4444 + expectedOwnerShares: 5_555, // 9999 - 4444 + }, + "Success: Withdraw some unlocked shares (~0.67% of total), 0 quantums in main vault, " + + "one quoting sub-vault with 0 leverage": { + mainVaultBalance: 0, + totalShares: 987_654, + owner: constants.AliceAccAddress.String(), + ownerTotalShares: 9999, + ownerLockedShares: 134, + vaults: []VaultSetup{ + { + id: constants.Vault_Clob0, + params: vaulttypes.VaultParams{ + Status: vaulttypes.VaultStatus_VAULT_STATUS_QUOTING, + }, + assetQuoteQuantums: big.NewInt(345), + positionBaseQuantums: big.NewInt(0), + clobPair: constants.ClobPair_Btc, + perpetual: constants.BtcUsd_20PercentInitial_10PercentMaintenance, + marketParam: constants.TestMarketParams[0], + marketPrice: constants.TestMarketPrices[0], + postWithdrawalEquity: big.NewInt(343), // 345 - 2 + }, + }, + sharesToWithdraw: 6666, + minQuoteQuantums: 2, + deliverTxFails: false, + redeemedQuoteQuantums: 2, // 345 * 6666 / 987654 ~= 2.32 ~= 2 (rounded down) + expectedTotalShares: 980_988, // 987654 - 6666 + expectedOwnerShares: 3333, // 9999 - 6666 + }, + "Success: Withdraw some unlocked shares (10% of total), 500 quantums in main vault, " + + "one stand-by sub-vault with 0 leverage, one close-only sub-vault with 1.5 leverage": { + mainVaultBalance: 500, + totalShares: 1_000, + owner: constants.AliceAccAddress.String(), + ownerTotalShares: 120, + ownerLockedShares: 15, + vaults: []VaultSetup{ + { + id: constants.Vault_Clob0, + params: vaulttypes.VaultParams{ + Status: vaulttypes.VaultStatus_VAULT_STATUS_STAND_BY, + }, + assetQuoteQuantums: big.NewInt(345), + positionBaseQuantums: big.NewInt(0), + clobPair: constants.ClobPair_Btc, + perpetual: constants.BtcUsd_20PercentInitial_10PercentMaintenance, + marketParam: constants.TestMarketParams[0], + marketPrice: constants.TestMarketPrices[0], + postWithdrawalEquity: big.NewInt(311), // 345 - 34 + }, + { + id: constants.Vault_Clob1, + params: vaulttypes.VaultParams{ + Status: vaulttypes.VaultStatus_VAULT_STATUS_CLOSE_ONLY, + QuotingParams: &vaulttypes.QuotingParams{ + Layers: 3, + SpreadMinPpm: 3_000, + SpreadBufferPpm: 1_500, + SkewFactorPpm: 3_000_000, + OrderSizePctPpm: 100_000, + OrderExpirationSeconds: 60, + ActivationThresholdQuoteQuantums: dtypes.NewInt(1_000_000_000), + }, + }, + // open_notional = 1_000_000_000 * 10^-9 * 3_000 * 10^6 = 3_000_000_000 + // leverage = 3_000_000_000 / (-1_000_000_000 + 3_000_000_000) = 1.5 + assetQuoteQuantums: big.NewInt(-1_000_000_000), + positionBaseQuantums: big.NewInt(1_000_000_000), + clobPair: constants.ClobPair_Eth, + perpetual: constants.EthUsd_20PercentInitial_10PercentMaintenance, + marketParam: constants.TestMarketParams[1], + marketPrice: constants.TestMarketPrices[1], + postWithdrawalEquity: big.NewInt(1_829_775_000), // 2_000_000_000 - 170_225_000 + }, + }, + sharesToWithdraw: 100, + minQuoteQuantums: 170_000_000, + deliverTxFails: false, + // Main vault withdrawal + sub-vault 0 withdrawal + sub-vault 1 withdrawal + // = 500 * 100 / 1_000 + 345 * 100 / 1_000 + 2_000_000_000 * 100 / 1_000 * (1 - 1191/8000) + // ~= 50 + 34 + 170225000 + // = 170225084 + redeemedQuoteQuantums: 170_225_084, + expectedTotalShares: 900, // 1_000 - 100 + expectedOwnerShares: 20, // 120 - 100 + }, + "Success: Withdraw all shares (100% of total), 500 quantums in main vault, " + + "one close-only sub-vault with 1.5 leverage": { + mainVaultBalance: 500, + totalShares: 1_000, + owner: constants.AliceAccAddress.String(), + ownerTotalShares: 1_000, + ownerLockedShares: 0, + vaults: []VaultSetup{ + { + id: constants.Vault_Clob1, + params: vaulttypes.VaultParams{ + Status: vaulttypes.VaultStatus_VAULT_STATUS_CLOSE_ONLY, + }, + // open_notional = 1_000_000_000 * 10^-9 * 3_000 * 10^6 = 3_000_000_000 + // leverage = 3_000_000_000 / (-1_000_000_000 + 3_000_000_000) = 1.5 + assetQuoteQuantums: big.NewInt(-1_000_000_000), + positionBaseQuantums: big.NewInt(1_000_000_000), + clobPair: constants.ClobPair_Eth, + perpetual: constants.EthUsd_20PercentInitial_10PercentMaintenance, + marketParam: constants.TestMarketParams[1], + marketPrice: constants.TestMarketPrices[1], + postWithdrawalEquity: big.NewInt(600_000_000), // 2_000_000_000 - 1_400_000_000 + }, + }, + sharesToWithdraw: 1_000, + minQuoteQuantums: 1_400_000_500, + deliverTxFails: false, + // Main vault withdrawal + sub-vault 0 withdrawal + // = 500 * 1_000 / 1_000 + 2_000_000_000 * 1_000 / 1_000 * (1 - leverage * imf) + // = 500 + 2_000_000_000 * (1 - 1.5 * 0.2) + redeemedQuoteQuantums: 1_400_000_500, + expectedTotalShares: 0, + expectedOwnerShares: 0, + }, + } + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + // Initialize tApp and ctx. + tApp := testapp.NewTestAppBuilder(t).WithGenesisDocFn(func() (genesis types.GenesisDoc) { + genesis = testapp.DefaultGenesis() + testapp.UpdateGenesisDocWithAppStateForModule( + &genesis, + func(genesisState *satypes.GenesisState) { + subaccounts := []satypes.Subaccount{ + { + Id: &vaulttypes.MegavaultMainSubaccount, + AssetPositions: []*satypes.AssetPosition{ + { + AssetId: assetstypes.AssetUsdc.Id, + Quantums: dtypes.NewIntFromUint64(tc.mainVaultBalance), + }, + }, + }, + } + for _, vault := range tc.vaults { + subaccounts = append(subaccounts, satypes.Subaccount{ + Id: vault.id.ToSubaccountId(), + AssetPositions: []*satypes.AssetPosition{ + { + AssetId: assetstypes.AssetUsdc.Id, + Quantums: dtypes.NewIntFromBigInt(vault.assetQuoteQuantums), + }, + }, + PerpetualPositions: []*satypes.PerpetualPosition{ + { + PerpetualId: vault.perpetual.Params.Id, + Quantums: dtypes.NewIntFromBigInt(vault.positionBaseQuantums), + }, + }, + }) + } + genesisState.Subaccounts = subaccounts + }, + ) + testapp.UpdateGenesisDocWithAppStateForModule( + &genesis, + func(genesisState *vaulttypes.GenesisState) { + genesisState.TotalShares = vaulttypes.NumShares{ + NumShares: dtypes.NewIntFromUint64(tc.totalShares), + } + genesisState.OwnerShares = []vaulttypes.OwnerShare{ + { + Owner: tc.owner, + Shares: vaulttypes.NumShares{ + NumShares: dtypes.NewIntFromUint64(tc.ownerTotalShares), + }, + }, + } + genesisState.AllOwnerShareUnlocks = []vaulttypes.OwnerShareUnlocks{ + { + OwnerAddress: tc.owner, + ShareUnlocks: []vaulttypes.ShareUnlock{ + { + Shares: vaulttypes.NumShares{ + NumShares: dtypes.NewIntFromUint64(tc.ownerLockedShares), + }, + UnlockBlockHeight: 7, // dummy height + }, + }, + }, + } + vaults := make([]vaulttypes.Vault, len(tc.vaults)) + for i, vault := range tc.vaults { + vaults[i] = vaulttypes.Vault{ + VaultId: vault.id, + VaultParams: vault.params, + } + } + genesisState.Vaults = vaults + }, + ) + // Initialize prices. + testapp.UpdateGenesisDocWithAppStateForModule( + &genesis, + func(genesisState *pricestypes.GenesisState) { + marketParams := make([]pricestypes.MarketParam, len(tc.vaults)) + marketPrices := make([]pricestypes.MarketPrice, len(tc.vaults)) + for i, vault := range tc.vaults { + vault.marketParam.Id = vault.id.Number + marketParams[i] = vault.marketParam + vault.marketPrice.Id = vault.id.Number + marketPrices[i] = vault.marketPrice + } + genesisState.MarketParams = marketParams + genesisState.MarketPrices = marketPrices + }, + ) + // Initialize perpetuals. + testapp.UpdateGenesisDocWithAppStateForModule( + &genesis, + func(genesisState *perptypes.GenesisState) { + genesisState.LiquidityTiers = constants.LiquidityTiers + perpetuals := make([]perptypes.Perpetual, len(tc.vaults)) + for i, vault := range tc.vaults { + vault.perpetual.Params.Id = vault.id.Number + perpetuals[i] = vault.perpetual + } + genesisState.Perpetuals = perpetuals + }, + ) + // Initialize clob pairs. + testapp.UpdateGenesisDocWithAppStateForModule( + &genesis, + func(genesisState *clobtypes.GenesisState) { + clobPairs := make([]clobtypes.ClobPair, len(tc.vaults)) + for i, vault := range tc.vaults { + vault.clobPair.Id = vault.id.Number + clobPairs[i] = vault.clobPair + } + genesisState.ClobPairs = clobPairs + }, + ) + return genesis + }).Build() + ctx := tApp.InitChain() + + // Construct message. + msgWithdrawFromMegavault := vaulttypes.MsgWithdrawFromMegavault{ + SubaccountId: satypes.SubaccountId{ + Owner: tc.owner, + Number: 0, + }, + Shares: vaulttypes.NumShares{ + NumShares: dtypes.NewIntFromUint64(tc.sharesToWithdraw), + }, + MinQuoteQuantums: dtypes.NewIntFromUint64(tc.minQuoteQuantums), + } + + preMegavaultEquity, err := tApp.App.VaultKeeper.GetMegavaultEquity(ctx) + require.NoError(t, err) + preOwnerEquity, err := tApp.App.VaultKeeper.GetSubaccountEquity(ctx, msgWithdrawFromMegavault.SubaccountId) + require.NoError(t, err) + + // Invoke CheckTx. + CheckTx_MsgWithdrawFromMegavault := testapp.MustMakeCheckTx( + ctx, + tApp.App, + testapp.MustMakeCheckTxOptions{ + AccAddressForSigning: tc.owner, + Gas: constants.TestGasLimit, + FeeAmt: constants.TestFeeCoins_5Cents, + }, + &msgWithdrawFromMegavault, + ) + checkTxResp := tApp.CheckTx(CheckTx_MsgWithdrawFromMegavault) + require.Conditionf(t, checkTxResp.IsOK, "Expected CheckTx to succeed. Response: %+v", checkTxResp) + + // Advance to next block (and check that DeliverTx is as expected). + nextBlock := uint32(ctx.BlockHeight()) + 1 + if tc.deliverTxFails { + // Check that DeliverTx fails on `msgDepositToMegavault`. + ctx = tApp.AdvanceToBlock(nextBlock, testapp.AdvanceToBlockOptions{ + ValidateFinalizeBlock: func( + context sdktypes.Context, + request abcitypes.RequestFinalizeBlock, + response abcitypes.ResponseFinalizeBlock, + ) (haltChain bool) { + for i, tx := range request.Txs { + if bytes.Equal(tx, CheckTx_MsgWithdrawFromMegavault.Tx) { + require.True(t, response.TxResults[i].IsErr()) + } else { + require.True(t, response.TxResults[i].IsOK()) + } + } + return false + }, + }) + } else { + ctx = tApp.AdvanceToBlock(nextBlock, testapp.AdvanceToBlockOptions{}) + } + + // Check total shares. + totalShares := tApp.App.VaultKeeper.GetTotalShares(ctx) + require.Equal( + t, + new(big.Int).SetUint64(tc.expectedTotalShares), + totalShares.NumShares.BigInt(), + ) + // Check owner shares. + ownerShares, exists := tApp.App.VaultKeeper.GetOwnerShares( + ctx, + tc.owner, + ) + if tc.expectedOwnerShares == 0 { + require.False(t, exists) + } else { + require.True(t, exists) + require.Equal( + t, + new(big.Int).SetUint64(tc.expectedOwnerShares), + ownerShares.NumShares.BigInt(), + ) + } + // Check equity of owner, megavault, and each sub-vault. + postOwnerEquity, err := tApp.App.VaultKeeper.GetSubaccountEquity(ctx, msgWithdrawFromMegavault.SubaccountId) + require.NoError(t, err) + postMegavaultEquity, err := tApp.App.VaultKeeper.GetMegavaultEquity(ctx) + require.NoError(t, err) + if tc.deliverTxFails { + require.Equal(t, preOwnerEquity, postOwnerEquity) + require.Equal(t, preMegavaultEquity, postMegavaultEquity) + } else { + require.Equal( + t, + preOwnerEquity.Uint64()+tc.redeemedQuoteQuantums, + postOwnerEquity.Uint64(), + ) + require.Equal( + t, + preMegavaultEquity.Uint64()-tc.redeemedQuoteQuantums, + postMegavaultEquity.Uint64(), + ) + } + for _, vault := range tc.vaults { + subVaultEquity, err := tApp.App.VaultKeeper.GetSubaccountEquity(ctx, *vault.id.ToSubaccountId()) + require.NoError(t, err) + require.Equal( + t, + vault.postWithdrawalEquity, + subVaultEquity, + ) + } + }) + } +} diff --git a/protocol/x/vault/keeper/orders.go b/protocol/x/vault/keeper/orders.go index fccb96f6e77..8faf869b47c 100644 --- a/protocol/x/vault/keeper/orders.go +++ b/protocol/x/vault/keeper/orders.go @@ -170,10 +170,17 @@ func (k Keeper) GetVaultClobOrders( } // Get vault leverage and equity. - leverage, equity, err := k.GetVaultLeverageAndEquity(ctx, vaultId, perpetual, marketPrice) + leverage, equity, err := k.GetVaultLeverageAndEquity(ctx, vaultId, &perpetual, &marketPrice) if err != nil { return orders, err } + if equity.Sign() <= 0 { + return orders, errorsmod.Wrap( + types.ErrNonPositiveEquity, + fmt.Sprintf("VaultId: %v", vaultId), + ) + } + leveragePpm := new(big.Int).Mul(leverage.Num(), lib.BigIntOneMillion()) leveragePpm = lib.BigDivCeil(leveragePpm, leverage.Denom()) diff --git a/protocol/x/vault/keeper/vault.go b/protocol/x/vault/keeper/vault.go index 7f68377f4f2..13fcfddeaf6 100644 --- a/protocol/x/vault/keeper/vault.go +++ b/protocol/x/vault/keeper/vault.go @@ -63,11 +63,12 @@ func (k Keeper) GetVaultEquity( // GetVaultLeverageAndEquity returns a vault's leverage and equity. // - leverage = open notional / equity. +// Note that `equity` can be negative and it's up to the caller to handle different scenarios. func (k Keeper) GetVaultLeverageAndEquity( ctx sdk.Context, vaultId types.VaultId, - perpetual perptypes.Perpetual, - marketPrice pricestypes.MarketPrice, + perpetual *perptypes.Perpetual, + marketPrice *pricestypes.MarketPrice, ) ( leverage *big.Rat, equity *big.Int, @@ -77,12 +78,6 @@ func (k Keeper) GetVaultLeverageAndEquity( if err != nil { return nil, nil, err } - if equity.Sign() <= 0 { - return nil, equity, errorsmod.Wrap( - types.ErrNonPositiveEquity, - fmt.Sprintf("VaultId: %v", vaultId), - ) - } inventory := k.GetVaultInventoryInPerpetual(ctx, vaultId, perpetual.GetId()) openNotional := lib.BaseToQuoteQuantums( diff --git a/protocol/x/vault/keeper/withdraw.go b/protocol/x/vault/keeper/withdraw.go index ac5ab5f1cd5..1cf4581d9ee 100644 --- a/protocol/x/vault/keeper/withdraw.go +++ b/protocol/x/vault/keeper/withdraw.go @@ -6,11 +6,16 @@ import ( errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/dydxprotocol/v4-chain/protocol/lib" + "github.com/dydxprotocol/v4-chain/protocol/lib/log" "github.com/dydxprotocol/v4-chain/protocol/lib/vault" + assetstypes "github.com/dydxprotocol/v4-chain/protocol/x/assets/types" + perptypes "github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/types" + pricestypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" + satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" "github.com/dydxprotocol/v4-chain/protocol/x/vault/types" ) -// GetVaultWithdrawalSlippagePpm returns the slippage that should be incurred from the specified +// GetVaultWithdrawalSlippage returns the slippage that should be incurred from the specified // vault on withdrawing `sharesToWithdraw` shares. // For example, if `sharesToWithdraw = 100` and `0.2` is returned, it means that withdrawing // 100 shares has a 20% slippage for the given `vaultId`. @@ -36,8 +41,11 @@ func (k Keeper) GetVaultWithdrawalSlippage( ctx sdk.Context, vaultId types.VaultId, sharesToWithdraw *big.Int, + totalShares *big.Int, + leverage *big.Rat, + perpetual *perptypes.Perpetual, + marketParam *pricestypes.MarketParam, ) (*big.Rat, error) { - totalShares := k.GetTotalShares(ctx).NumShares.BigInt() if sharesToWithdraw.Sign() <= 0 || sharesToWithdraw.Cmp(totalShares) > 0 { return nil, errorsmod.Wrapf( types.ErrInvalidSharesToWithdraw, @@ -52,16 +60,6 @@ func (k Keeper) GetVaultWithdrawalSlippage( return nil, types.ErrVaultParamsNotFound } - _, perpetual, marketParam, marketPrice, err := k.GetVaultClobPerpAndMarket(ctx, vaultId) - if err != nil { - return nil, err - } - - // Get vault leverage. - leverage, _, err := k.GetVaultLeverageAndEquity(ctx, vaultId, perpetual, marketPrice) - if err != nil { - return nil, err - } // No leverage, no slippage. if leverage.Sign() == 0 { return lib.BigRat0(), nil @@ -108,7 +106,7 @@ func (k Keeper) GetVaultWithdrawalSlippage( ) estimatedSlippage = lib.BigRatMulPpm( estimatedSlippage, - vault.SpreadPpm("ingParams, &marketParam), + vault.SpreadPpm("ingParams, marketParam), ) // Return min(simple_slippage, estimated_slippage). @@ -117,3 +115,168 @@ func (k Keeper) GetVaultWithdrawalSlippage( estimatedSlippage, ), nil } + +// WithdrawFromMegavault withdraws from megavault to a subaccount. +func (k Keeper) WithdrawFromMegavault( + ctx sdk.Context, + toSubaccount satypes.SubaccountId, + sharesToWithdraw *big.Int, + minQuoteQuantums *big.Int, +) (redeemedQuoteQuantums *big.Int, err error) { + // 1. Check that the owner is withdrawing less that or equal to their unlocked shares. + ownerShares, exists := k.GetOwnerShares(ctx, toSubaccount.Owner) + if !exists { + return nil, types.ErrOwnerNotFound + } + ownerShareUnlocks, _ := k.GetOwnerShareUnlocks(ctx, toSubaccount.Owner) + ownerSharesAfterWithdrawal := ownerShares.NumShares.BigInt() + ownerSharesAfterWithdrawal.Sub(ownerSharesAfterWithdrawal, sharesToWithdraw) + ownerLockedShares := ownerShareUnlocks.GetTotalLockedShares() + if ownerSharesAfterWithdrawal.Cmp(ownerLockedShares) < 0 { + return nil, errorsmod.Wrapf( + types.ErrInsufficientWithdrawableShares, + "shares to withdraw: %s, owner total shares: %s, owner locked shares: %s", + sharesToWithdraw, + ownerShares, + ownerLockedShares, + ) + } + + // 2. Redeem from main vault. + totalShares := k.GetTotalShares(ctx).NumShares.BigInt() + redeemedQuoteQuantums, err = k.GetSubaccountEquity(ctx, types.MegavaultMainSubaccount) + if err != nil { + log.ErrorLogWithError(ctx, "Failed to get megavault main vault equity", err) + return nil, err + } + redeemedQuoteQuantums.Mul(redeemedQuoteQuantums, sharesToWithdraw) + redeemedQuoteQuantums.Quo(redeemedQuoteQuantums, totalShares) + + // 3. Redeem from each sub vault. + vaultParamsIterator := k.getVaultParamsIterator(ctx) + defer vaultParamsIterator.Close() + for ; vaultParamsIterator.Valid(); vaultParamsIterator.Next() { + vaultId, err := types.GetVaultIdFromStateKey(vaultParamsIterator.Key()) + if err != nil { + log.ErrorLogWithError(ctx, "Failed to get vault ID from state key", err) + continue + } + var vaultParams types.VaultParams + k.cdc.MustUnmarshal(vaultParamsIterator.Value(), &vaultParams) + + _, perpetual, marketParam, marketPrice, err := k.GetVaultClobPerpAndMarket(ctx, *vaultId) + if err != nil { + log.ErrorLogWithError(ctx, "Failed to get perpetual and market", err, "Vault ID", vaultId) + continue + } + leverage, equity, err := k.GetVaultLeverageAndEquity(ctx, *vaultId, &perpetual, &marketPrice) + if err != nil { + log.ErrorLogWithError(ctx, "Failed to get vault leverage and equity", err, "Vault ID", vaultId) + continue + } + // Skip if equity is non-positive. + if equity.Sign() <= 0 { + continue + } + + slippage, err := k.GetVaultWithdrawalSlippage( + ctx, + *vaultId, + sharesToWithdraw, + totalShares, + leverage, + &perpetual, + &marketParam, + ) + if err != nil { + log.ErrorLogWithError( + ctx, + "Failed to get vault withdrawal slippage", + err, + "Vault ID", + vaultId, + ) + continue + } + + // Transfer `equity * shares / totalShares * (1 - slippage)` from sub vault to main vault. + redeemedFromSubVault := new(big.Rat).SetFrac(equity, big.NewInt(1)) + redeemedFromSubVault.Mul(redeemedFromSubVault, new(big.Rat).SetFrac(sharesToWithdraw, totalShares)) + redeemedFromSubVault.Mul(redeemedFromSubVault, new(big.Rat).Sub(lib.BigRat1(), slippage)) + quantumsToTransfer := new(big.Int).Quo(redeemedFromSubVault.Num(), redeemedFromSubVault.Denom()) + + err = k.subaccountsKeeper.TransferFundsFromSubaccountToSubaccount( + ctx, + *vaultId.ToSubaccountId(), + types.MegavaultMainSubaccount, + assetstypes.AssetUsdc.Id, + quantumsToTransfer, + ) + if err != nil { + log.ErrorLogWithError( + ctx, + "Failed to transfer from sub vault to main vault", + err, + "Vault ID", + vaultId, + "Quantums", + quantumsToTransfer, + ) + continue + } + + // Increment total redeemed quote quantums. + redeemedQuoteQuantums.Add(redeemedQuoteQuantums, quantumsToTransfer) + } + + // 4. Return error if less than min quote quantums are redeemed. + if redeemedQuoteQuantums.Cmp(minQuoteQuantums) < 0 { + return nil, errorsmod.Wrapf( + types.ErrInsufficientRedeemedQuoteQuantums, + "redeemed quote quantums: %s, min quote quantums: %s", + redeemedQuoteQuantums, + minQuoteQuantums, + ) + } + + // 5. Transfer from main vault to destination subaccount. + err = k.subaccountsKeeper.TransferFundsFromSubaccountToSubaccount( + ctx, + types.MegavaultMainSubaccount, + toSubaccount, + assetstypes.AssetUsdc.Id, + redeemedQuoteQuantums, + ) + if err != nil { + log.ErrorLogWithError( + ctx, + "Failed to transfer from main vault to subaccount", + err, + "Subaccount", + toSubaccount, + "Quantums", + redeemedQuoteQuantums, + ) + return nil, err + } + + // 6. Decrement total and owner shares. + err = k.SetTotalShares( + ctx, + types.BigIntToNumShares(new(big.Int).Sub(totalShares, sharesToWithdraw)), + ) + if err != nil { + return nil, err + } + if ownerSharesAfterWithdrawal.Sign() == 0 { + store := k.getOwnerSharesStore(ctx) + store.Delete([]byte(toSubaccount.Owner)) + } else { + err := k.SetOwnerShares(ctx, toSubaccount.Owner, types.BigIntToNumShares(ownerSharesAfterWithdrawal)) + if err != nil { + return nil, err + } + } + + return redeemedQuoteQuantums, nil +} diff --git a/protocol/x/vault/keeper/withdraw_test.go b/protocol/x/vault/keeper/withdraw_test.go index f41e69fb266..a7d713ea6af 100644 --- a/protocol/x/vault/keeper/withdraw_test.go +++ b/protocol/x/vault/keeper/withdraw_test.go @@ -5,15 +5,11 @@ import ( "testing" "github.com/cometbft/cometbft/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" - testutil "github.com/dydxprotocol/v4-chain/protocol/testutil/util" - assettypes "github.com/dydxprotocol/v4-chain/protocol/x/assets/types" clobtypes "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" perptypes "github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/types" pricestypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" - satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" vaulttypes "github.com/dydxprotocol/v4-chain/protocol/x/vault/types" "github.com/stretchr/testify/require" ) @@ -34,8 +30,7 @@ func TestGetVaultWithdrawalSlippage(t *testing.T) { spreadBufferPpm uint32 minPriceChangePpm uint32 // leverage. - assetQuoteQuantums *big.Int - positionBaseQuantums *big.Int + leverage *big.Rat // total shares. totalShares *big.Int // function input. @@ -46,30 +41,26 @@ func TestGetVaultWithdrawalSlippage(t *testing.T) { expectedErr string }{ "Success: leverage 0, skew 2, spread 0.003, withdraw 10%": { - skewFactorPpm: 2_000_000, - spreadMinPpm: 2_000, - spreadBufferPpm: 1_500, - minPriceChangePpm: 1_500, - assetQuoteQuantums: big.NewInt(1_000_000_000), // 1,000 USDC - positionBaseQuantums: big.NewInt(0), - vaultId: testVaultId, - sharesToWithdraw: big.NewInt(10), - totalShares: big.NewInt(100), + skewFactorPpm: 2_000_000, + spreadMinPpm: 2_000, + spreadBufferPpm: 1_500, + minPriceChangePpm: 1_500, + leverage: big.NewRat(0, 1), + vaultId: testVaultId, + sharesToWithdraw: big.NewInt(10), + totalShares: big.NewInt(100), // no slippage when leverage is 0. expectedSlippage: big.NewRat(0, 1), }, "Success: leverage 0.00003, skew 3, spread 0.005, withdraw 9_999_999 out of 10_000_000 shares": { - skewFactorPpm: 3_000_000, - spreadMinPpm: 5_000, - spreadBufferPpm: 1_500, - minPriceChangePpm: 1_500, - assetQuoteQuantums: big.NewInt(999_970_000), - positionBaseQuantums: big.NewInt(10_000), // 1 ETH - vaultId: testVaultId, - sharesToWithdraw: big.NewInt(9_999_999), - totalShares: big.NewInt(10_000_000), - // open_notional = 10_000 * 10^-9 * 3_000 * 10^6 = 30_000 - // leverage = 30_000 / (999_700_000 + 3_000_000) = 0.00003 + skewFactorPpm: 3_000_000, + spreadMinPpm: 5_000, + spreadBufferPpm: 1_500, + minPriceChangePpm: 1_500, + leverage: big.NewRat(3, 100_000), + vaultId: testVaultId, + sharesToWithdraw: big.NewInt(9_999_999), + totalShares: big.NewInt(10_000_000), // posterior_leverage = 0.00003 * 10_000_000 / (10_000_000 - 9_999_999) = 300 // integral // = skew_antiderivative(skew_factor, posterior_leverage) - skew_antiderivative(skew_factor, leverage) @@ -84,17 +75,14 @@ func TestGetVaultWithdrawalSlippage(t *testing.T) { expectedSlippage: big.NewRat(6, 1_000_000), }, "Success: leverage 0.000003, skew 3, spread 0.005, withdraw 9_999_999 out of 10_000_000 shares": { - skewFactorPpm: 3_000_000, - spreadMinPpm: 5_000, - spreadBufferPpm: 1_500, - minPriceChangePpm: 1_500, - assetQuoteQuantums: big.NewInt(999_997_000), - positionBaseQuantums: big.NewInt(1_000), // 1 ETH - vaultId: testVaultId, - sharesToWithdraw: big.NewInt(9_999_999), - totalShares: big.NewInt(10_000_000), - // open_notional = 1_000 * 10^-9 * 3_000 * 10^6 = 3_000 - // leverage = 3_000 / (999_997_000 + 3_000) = 0.000003 + skewFactorPpm: 3_000_000, + spreadMinPpm: 5_000, + spreadBufferPpm: 1_500, + minPriceChangePpm: 1_500, + leverage: big.NewRat(3, 1_000_000), + vaultId: testVaultId, + sharesToWithdraw: big.NewInt(9_999_999), + totalShares: big.NewInt(10_000_000), // posterior_leverage = 0.000003 * 10_000_000 / (10_000_000 - 9_999_999) = 30 // integral // = skew_antiderivative(skew_factor, posterior_leverage) - skew_antiderivative(skew_factor, leverage) @@ -110,17 +98,14 @@ func TestGetVaultWithdrawalSlippage(t *testing.T) { expectedSlippage: big.NewRat(3, 5_000_000), }, "Success: leverage 0.5, skew 2, spread 0.003, withdraw 10%": { - skewFactorPpm: 2_000_000, - spreadMinPpm: 2_000, - spreadBufferPpm: 1_500, - minPriceChangePpm: 1_500, - assetQuoteQuantums: big.NewInt(3_000_000_000), // 3,000 USDC - positionBaseQuantums: big.NewInt(1_000_000_000), // 1 ETH - vaultId: testVaultId, - sharesToWithdraw: big.NewInt(100_000), - totalShares: big.NewInt(1_000_000), - // open_notional = 1_000_000_000 * 10^-9 * 3_000 * 10^6 = 3_000_000_000 - // leverage = 3_000_000_000 / (3_000_000_000 + 3_000_000_000) = 0.5 + skewFactorPpm: 2_000_000, + spreadMinPpm: 2_000, + spreadBufferPpm: 1_500, + minPriceChangePpm: 1_500, + leverage: big.NewRat(1, 2), + vaultId: testVaultId, + sharesToWithdraw: big.NewInt(100_000), + totalShares: big.NewInt(1_000_000), // posterior_leverage = 0.5 * 1_000_000 / (1_000_000 - 100_000) = 5 / 9 // integral // = skew_antiderivative(skew_factor, posterior_leverage) - skew_antiderivative(skew_factor, leverage) @@ -135,17 +120,14 @@ func TestGetVaultWithdrawalSlippage(t *testing.T) { expectedSlippage: big.NewRat(1_027, 162_000), }, "Success: leverage 1.5, skew 2, spread 0.003, withdraw 0.0001%": { - skewFactorPpm: 2_000_000, - spreadMinPpm: 2_000, - spreadBufferPpm: 1_500, - minPriceChangePpm: 1_500, - assetQuoteQuantums: big.NewInt(-1_000_000_000), // -1,000 USDC - positionBaseQuantums: big.NewInt(1_000_000_000), // 1 ETH - vaultId: testVaultId, - sharesToWithdraw: big.NewInt(1), - totalShares: big.NewInt(1_000_000), - // open_notional = 1_000_000_000 * 10^-9 * 3_000 * 10^6 = 3_000_000_000 - // leverage = 3_000_000_000 / (-1_000_000_000 + 3_000_000_000) = 1.5 + skewFactorPpm: 2_000_000, + spreadMinPpm: 2_000, + spreadBufferPpm: 1_500, + minPriceChangePpm: 1_500, + leverage: big.NewRat(3, 2), + vaultId: testVaultId, + sharesToWithdraw: big.NewInt(1), + totalShares: big.NewInt(1_000_000), // posterior_leverage = 1.5 * 1_000_000 / (1_000_000 - 1) = 500_000/333_333 // integral // = skew_antiderivative(skew_factor, posterior_leverage) - skew_antiderivative(skew_factor, leverage) @@ -161,17 +143,14 @@ func TestGetVaultWithdrawalSlippage(t *testing.T) { expectedSlippage: big.NewRat(5333326666669, 74073925926000), }, "Success: leverage 1.5, skew 3, spread 0.003, withdraw 10%": { - skewFactorPpm: 3_000_000, - spreadMinPpm: 2_000, - spreadBufferPpm: 1_500, - minPriceChangePpm: 1_500, - assetQuoteQuantums: big.NewInt(-1_000_000_000), // -1,000 USDC - positionBaseQuantums: big.NewInt(1_000_000_000), // 1 ETH - vaultId: testVaultId, - sharesToWithdraw: big.NewInt(100_000), - totalShares: big.NewInt(1_000_000), - // open_notional = 1_000_000_000 * 10^-9 * 3_000 * 10^6 = 3_000_000_000 - // leverage = 3_000_000_000 / (-1_000_000_000 + 3_000_000_000) = 1.5 + skewFactorPpm: 3_000_000, + spreadMinPpm: 2_000, + spreadBufferPpm: 1_500, + minPriceChangePpm: 1_500, + leverage: big.NewRat(3, 2), + vaultId: testVaultId, + sharesToWithdraw: big.NewInt(100_000), + totalShares: big.NewInt(1_000_000), // posterior_leverage = 1.5 * 1_000_000 / (1_000_000 - 100_000) = 5/3 // integral // = skew_antiderivative(skew_factor, posterior_leverage) - skew_antiderivative(skew_factor, leverage) @@ -187,17 +166,14 @@ func TestGetVaultWithdrawalSlippage(t *testing.T) { expectedSlippage: big.NewRat(1_191, 8_000), }, "Success: leverage 1.5, skew 3, spread 0.003, withdraw 50%": { - skewFactorPpm: 3_000_000, - spreadMinPpm: 2_000, - spreadBufferPpm: 1_500, - minPriceChangePpm: 1_500, - assetQuoteQuantums: big.NewInt(-1_000_000_000), // -1,000 USDC - positionBaseQuantums: big.NewInt(1_000_000_000), // 1 ETH - vaultId: testVaultId, - sharesToWithdraw: big.NewInt(500_000), - totalShares: big.NewInt(1_000_000), - // open_notional = 1_000_000_000 * 10^-9 * 3_000 * 10^6 = 3_000_000_000 - // leverage = 3_000_000_000 / (-1_000_000_000 + 3_000_000_000) = 1.5 + skewFactorPpm: 3_000_000, + spreadMinPpm: 2_000, + spreadBufferPpm: 1_500, + minPriceChangePpm: 1_500, + leverage: big.NewRat(3, 2), + vaultId: testVaultId, + sharesToWithdraw: big.NewInt(500_000), + totalShares: big.NewInt(1_000_000), // posterior_leverage = 1.5 * 1_000_000 / (1_000_000 - 500_000) = 3 // integral // = skew_antiderivative(skew_factor, posterior_leverage) - skew_antiderivative(skew_factor, leverage) @@ -213,17 +189,15 @@ func TestGetVaultWithdrawalSlippage(t *testing.T) { expectedSlippage: big.NewRat(2_223, 8_000), }, "Success: leverage -1.5, skew 3, spread 0.003, withdraw 50%, slippage is same as when leverage is 1.5": { - skewFactorPpm: 3_000_000, - spreadMinPpm: 2_000, - spreadBufferPpm: 1_500, - minPriceChangePpm: 1_500, - assetQuoteQuantums: big.NewInt(5_000_000_000), // 5,000 USDC - positionBaseQuantums: big.NewInt(-1_000_000_000), // -1 ETH - vaultId: testVaultId, - sharesToWithdraw: big.NewInt(1_111), - totalShares: big.NewInt(2_222), - // open_notional = -1_000_000_000 * 10^-9 * 3_000 * 10^6 = -3_000_000_000 - // |leverage| = |-3_000_000_000 / (5_000_000_000 + -3_000_000_000)| = |-1.5| = 1.5 + skewFactorPpm: 3_000_000, + spreadMinPpm: 2_000, + spreadBufferPpm: 1_500, + minPriceChangePpm: 1_500, + leverage: big.NewRat(-3, 2), + vaultId: testVaultId, + sharesToWithdraw: big.NewInt(1_111), + totalShares: big.NewInt(2_222), + // |leverage| = |-1.5| = 1.5 // posterior_leverage = 1.5 * 2_222 / (2_222 - 1_111) = 3 // integral // = skew_antiderivative(skew_factor, posterior_leverage) - skew_antiderivative(skew_factor, leverage) @@ -239,17 +213,14 @@ func TestGetVaultWithdrawalSlippage(t *testing.T) { expectedSlippage: big.NewRat(2_223, 8_000), }, "Success: leverage 1.5, skew 3, spread 0.005, withdraw 50%": { - skewFactorPpm: 3_000_000, - spreadMinPpm: 5_000, - spreadBufferPpm: 1_500, - minPriceChangePpm: 1_500, - assetQuoteQuantums: big.NewInt(-1_000_000_000), // -1,000 USDC - positionBaseQuantums: big.NewInt(1_000_000_000), // 1 ETH - vaultId: testVaultId, - sharesToWithdraw: big.NewInt(2_345_678), - totalShares: big.NewInt(4_691_356), - // open_notional = 1_000_000_000 * 10^-9 * 3_000 * 10^6 = 3_000_000_000 - // leverage = 3_000_000_000 / (-1_000_000_000 + 3_000_000_000) = 1.5 + skewFactorPpm: 3_000_000, + spreadMinPpm: 5_000, + spreadBufferPpm: 1_500, + minPriceChangePpm: 1_500, + leverage: big.NewRat(3, 2), + vaultId: testVaultId, + sharesToWithdraw: big.NewInt(2_345_678), + totalShares: big.NewInt(4_691_356), // posterior_leverage = 1.5 * 4_691_356 / (4_691_356 - 2_345_678) = 3 // integral // = skew_antiderivative(skew_factor, posterior_leverage) - skew_antiderivative(skew_factor, leverage) @@ -264,32 +235,26 @@ func TestGetVaultWithdrawalSlippage(t *testing.T) { expectedSlippage: big.NewRat(3, 10), }, "Success: leverage 1.5, skew 3, spread 0.005, withdraw 100%": { - skewFactorPpm: 3_000_000, - spreadMinPpm: 5_000, - spreadBufferPpm: 1_500, - minPriceChangePpm: 1_500, - assetQuoteQuantums: big.NewInt(-1_000_000_000), // -1,000 USDC - positionBaseQuantums: big.NewInt(1_000_000_000), // 1 ETH - vaultId: testVaultId, - sharesToWithdraw: big.NewInt(2_345_678), - totalShares: big.NewInt(2_345_678), - // open_notional = 1_000_000_000 * 10^-9 * 3_000 * 10^6 = 3_000_000_000 - // leverage = 3_000_000_000 / (-1_000_000_000 + 3_000_000_000) = 1.5 + skewFactorPpm: 3_000_000, + spreadMinPpm: 5_000, + spreadBufferPpm: 1_500, + minPriceChangePpm: 1_500, + leverage: big.NewRat(3, 2), + vaultId: testVaultId, + sharesToWithdraw: big.NewInt(2_345_678), + totalShares: big.NewInt(2_345_678), // slippage = leverage * imf = 1.5 * 0.2 = 0.3 expectedSlippage: big.NewRat(3, 10), }, "Success: leverage 3, skew 2, spread 0.003, withdraw 1 out of 10 million shares": { - skewFactorPpm: 2_000_000, - spreadMinPpm: 2_000, - spreadBufferPpm: 1_500, - minPriceChangePpm: 1_500, - assetQuoteQuantums: big.NewInt(-2_000_000_000), // -2,000 USDC - positionBaseQuantums: big.NewInt(1_000_000_000), // 1 ETH - vaultId: testVaultId, - sharesToWithdraw: big.NewInt(1), - totalShares: big.NewInt(10_000_000), - // open_notional = 1_000_000_000 * 10^-9 * 3_000 * 10^6 = 3_000_000_000 - // leverage = 3_000_000_000 / (-2_000_000_000 + 3_000_000_000) = 3 + skewFactorPpm: 2_000_000, + spreadMinPpm: 2_000, + spreadBufferPpm: 1_500, + minPriceChangePpm: 1_500, + leverage: big.NewRat(3, 1), + vaultId: testVaultId, + sharesToWithdraw: big.NewInt(1), + totalShares: big.NewInt(10_000_000), // posterior_leverage = 3 * 10_000_000 / (10_000_000 - 1) = 3.0000003 // integral // = skew_antiderivative(skew_factor, posterior_leverage) - skew_antiderivative(skew_factor, leverage) @@ -305,17 +270,14 @@ func TestGetVaultWithdrawalSlippage(t *testing.T) { expectedSlippage: big.NewRat(1_633_333_146_666_673, 3_703_702_962_963_000), }, "Success: leverage 3, skew 2, spread 0.003, withdraw 1234 out of 12345 shares": { - skewFactorPpm: 2_000_000, - spreadMinPpm: 3_000, - spreadBufferPpm: 1_500, - minPriceChangePpm: 1_000, - assetQuoteQuantums: big.NewInt(-2_000_000_000), // -2,000 USDC - positionBaseQuantums: big.NewInt(1_000_000_000), // 1 ETH - vaultId: testVaultId, - sharesToWithdraw: big.NewInt(1_234), - totalShares: big.NewInt(12_345), - // open_notional = 1_000_000_000 * 10^-9 * 3_000 * 10^6 = 3_000_000_000 - // leverage = 3_000_000_000 / (-2_000_000_000 + 3_000_000_000) = 3 + skewFactorPpm: 2_000_000, + spreadMinPpm: 3_000, + spreadBufferPpm: 1_500, + minPriceChangePpm: 1_000, + leverage: big.NewRat(3, 1), + vaultId: testVaultId, + sharesToWithdraw: big.NewInt(1_234), + totalShares: big.NewInt(12_345), // posterior_leverage = 3 * 12345 / (12345 - 1234) = 37035/11111 // integral // = skew_antiderivative(skew_factor, posterior_leverage) - skew_antiderivative(skew_factor, leverage) @@ -332,17 +294,14 @@ func TestGetVaultWithdrawalSlippage(t *testing.T) { expectedSlippage: big.NewRat(59_790_561_381, 123_454_321_000), }, "Success: leverage 3, skew 2, spread 0.003, withdraw 50%": { - skewFactorPpm: 2_000_000, - spreadMinPpm: 2_000, - spreadBufferPpm: 1_500, - minPriceChangePpm: 1_500, - assetQuoteQuantums: big.NewInt(-2_000_000_000), // -2,000 USDC - positionBaseQuantums: big.NewInt(1_000_000_000), // 1 ETH - vaultId: testVaultId, - sharesToWithdraw: big.NewInt(222_222), - totalShares: big.NewInt(444_444), - // open_notional = 1_000_000_000 * 10^-9 * 3_000 * 10^6 = 3_000_000_000 - // leverage = 3_000_000_000 / (-2_000_000_000 + 3_000_000_000) = 3 + skewFactorPpm: 2_000_000, + spreadMinPpm: 2_000, + spreadBufferPpm: 1_500, + minPriceChangePpm: 1_500, + leverage: big.NewRat(3, 1), + vaultId: testVaultId, + sharesToWithdraw: big.NewInt(222_222), + totalShares: big.NewInt(444_444), // posterior_leverage = 3 * 444_444 / (444_444 - 222_222) = 6 // integral // = skew_antiderivative(skew_factor, posterior_leverage) - skew_antiderivative(skew_factor, leverage) @@ -359,17 +318,14 @@ func TestGetVaultWithdrawalSlippage(t *testing.T) { expectedSlippage: big.NewRat(3, 5), }, "Success: leverage 3, skew 2, spread 0.003, withdraw 99.9999%": { - skewFactorPpm: 2_000_000, - spreadMinPpm: 2_000, - spreadBufferPpm: 1_500, - minPriceChangePpm: 1_500, - assetQuoteQuantums: big.NewInt(-2_000_000_000), // -2,000 USDC - positionBaseQuantums: big.NewInt(1_000_000_000), // 1 ETH - vaultId: testVaultId, - sharesToWithdraw: big.NewInt(999_999), - totalShares: big.NewInt(1_000_000), - // open_notional = 1_000_000_000 * 10^-9 * 3_000 * 10^6 = 3_000_000_000 - // leverage = 3_000_000_000 / (-2_000_000_000 + 3_000_000_000) = 3 + skewFactorPpm: 2_000_000, + spreadMinPpm: 2_000, + spreadBufferPpm: 1_500, + minPriceChangePpm: 1_500, + leverage: big.NewRat(3, 1), + vaultId: testVaultId, + sharesToWithdraw: big.NewInt(999_999), + totalShares: big.NewInt(1_000_000), // posterior_leverage = 3 * 1_000_000 / (1_000_000 - 999_999) = 3_000_000 // integral // = skew_antiderivative(skew_factor, posterior_leverage) - skew_antiderivative(skew_factor, leverage) @@ -385,52 +341,48 @@ func TestGetVaultWithdrawalSlippage(t *testing.T) { expectedSlippage: big.NewRat(3, 5), }, "Error: vault not found": { - skewFactorPpm: 2_000_000, - spreadMinPpm: 2_000, - spreadBufferPpm: 1_500, - minPriceChangePpm: 1_500, - assetQuoteQuantums: big.NewInt(-2_000_000_000), // -2,000 USDC - positionBaseQuantums: big.NewInt(1_000_000_000), // 1 ETH - vaultId: constants.Vault_Clob0, // non-existent vault - sharesToWithdraw: big.NewInt(10), - totalShares: big.NewInt(100), - expectedErr: vaulttypes.ErrVaultParamsNotFound.Error(), + skewFactorPpm: 2_000_000, + spreadMinPpm: 2_000, + spreadBufferPpm: 1_500, + minPriceChangePpm: 1_500, + leverage: big.NewRat(1, 1), + vaultId: constants.Vault_Clob0, // non-existent vault + sharesToWithdraw: big.NewInt(10), + totalShares: big.NewInt(100), + expectedErr: vaulttypes.ErrVaultParamsNotFound.Error(), }, "Error: negative shares to withdraw": { - skewFactorPpm: 2_000_000, - spreadMinPpm: 2_000, - spreadBufferPpm: 1_500, - minPriceChangePpm: 1_500, - assetQuoteQuantums: big.NewInt(-2_000_000_000), // -2,000 USDC - positionBaseQuantums: big.NewInt(1_000_000_000), // 1 ETH - vaultId: testVaultId, - sharesToWithdraw: big.NewInt(-1), - totalShares: big.NewInt(100), - expectedErr: vaulttypes.ErrInvalidSharesToWithdraw.Error(), + skewFactorPpm: 2_000_000, + spreadMinPpm: 2_000, + spreadBufferPpm: 1_500, + minPriceChangePpm: 1_500, + leverage: big.NewRat(1, 1), + vaultId: testVaultId, + sharesToWithdraw: big.NewInt(-1), + totalShares: big.NewInt(100), + expectedErr: vaulttypes.ErrInvalidSharesToWithdraw.Error(), }, "Error: zero shares to withdraw": { - skewFactorPpm: 2_000_000, - spreadMinPpm: 2_000, - spreadBufferPpm: 1_500, - minPriceChangePpm: 1_500, - assetQuoteQuantums: big.NewInt(-2_000_000_000), // -2,000 USDC - positionBaseQuantums: big.NewInt(1_000_000_000), // 1 ETH - vaultId: testVaultId, - sharesToWithdraw: big.NewInt(0), - totalShares: big.NewInt(100), - expectedErr: vaulttypes.ErrInvalidSharesToWithdraw.Error(), + skewFactorPpm: 2_000_000, + spreadMinPpm: 2_000, + spreadBufferPpm: 1_500, + minPriceChangePpm: 1_500, + leverage: big.NewRat(1, 1), + vaultId: testVaultId, + sharesToWithdraw: big.NewInt(0), + totalShares: big.NewInt(100), + expectedErr: vaulttypes.ErrInvalidSharesToWithdraw.Error(), }, "Error: shares to withdraw greater than total shares": { - skewFactorPpm: 2_000_000, - spreadMinPpm: 2_000, - spreadBufferPpm: 1_500, - minPriceChangePpm: 1_500, - assetQuoteQuantums: big.NewInt(-2_000_000_000), // -2,000 USDC - positionBaseQuantums: big.NewInt(1_000_000_000), // 1 ETH - vaultId: testVaultId, - sharesToWithdraw: big.NewInt(1_000_001), - totalShares: big.NewInt(1_000_000), - expectedErr: vaulttypes.ErrInvalidSharesToWithdraw.Error(), + skewFactorPpm: 2_000_000, + spreadMinPpm: 2_000, + spreadBufferPpm: 1_500, + minPriceChangePpm: 1_500, + leverage: big.NewRat(-1, 1), + vaultId: testVaultId, + sharesToWithdraw: big.NewInt(1_000_001), + totalShares: big.NewInt(1_000_000), + expectedErr: vaulttypes.ErrInvalidSharesToWithdraw.Error(), }, } for name, tc := range tests { @@ -481,37 +433,20 @@ func TestGetVaultWithdrawalSlippage(t *testing.T) { genesisState.ClobPairs = []clobtypes.ClobPair{testClobPair} }, ) - // Set up vault asset and perpetual positions. - testapp.UpdateGenesisDocWithAppStateForModule( - &genesis, - func(genesisState *satypes.GenesisState) { - genesisState.Subaccounts = []satypes.Subaccount{ - { - Id: tc.vaultId.ToSubaccountId(), - AssetPositions: []*satypes.AssetPosition{ - { - AssetId: assettypes.AssetUsdc.Id, - Quantums: dtypes.NewIntFromBigInt(tc.assetQuoteQuantums), - }, - }, - PerpetualPositions: []*satypes.PerpetualPosition{ - testutil.CreateSinglePerpetualPosition( - testPerpetual.Params.Id, - tc.positionBaseQuantums, - big.NewInt(0), - big.NewInt(0), - ), - }, - }, - } - }, - ) return genesis }).Build() ctx := tApp.InitChain() k := tApp.App.VaultKeeper - slippage, err := k.GetVaultWithdrawalSlippage(ctx, tc.vaultId, tc.sharesToWithdraw) + slippage, err := k.GetVaultWithdrawalSlippage( + ctx, + tc.vaultId, + tc.sharesToWithdraw, + tc.totalShares, + tc.leverage, + &testPerpetual, + &testMarketParam, + ) if tc.expectedErr == "" { require.NoError(t, err) diff --git a/protocol/x/vault/types/errors.go b/protocol/x/vault/types/errors.go index ecd05010b72..b68028ece25 100644 --- a/protocol/x/vault/types/errors.go +++ b/protocol/x/vault/types/errors.go @@ -135,4 +135,14 @@ var ( 26, "Authority must be a module authority or operator", ) + ErrInsufficientWithdrawableShares = errorsmod.Register( + ModuleName, + 27, + "Insufficient withdrawable shares", + ) + ErrInsufficientRedeemedQuoteQuantums = errorsmod.Register( + ModuleName, + 28, + "Insufficient redeemed quote quantums", + ) ) diff --git a/protocol/x/vault/types/tx.pb.go b/protocol/x/vault/types/tx.pb.go index f89fb01e87b..9eebd4db2fb 100644 --- a/protocol/x/vault/types/tx.pb.go +++ b/protocol/x/vault/types/tx.pb.go @@ -127,6 +127,105 @@ func (m *MsgDepositToMegavaultResponse) GetMintedShares() NumShares { return NumShares{} } +// MsgWithdrawFromMegavault withdraws the specified shares from megavault to +// a subaccount. +type MsgWithdrawFromMegavault struct { + // The subaccount to withdraw to. + SubaccountId types.SubaccountId `protobuf:"bytes,1,opt,name=subaccount_id,json=subaccountId,proto3" json:"subaccount_id"` + // Number of shares to withdraw. + Shares NumShares `protobuf:"bytes,2,opt,name=shares,proto3" json:"shares"` + // The minimum number of quote quantums above shares should redeem, i.e. + // transaction fails if above shares redeem less than min_quote_quantums. + MinQuoteQuantums github_com_dydxprotocol_v4_chain_protocol_dtypes.SerializableInt `protobuf:"bytes,3,opt,name=min_quote_quantums,json=minQuoteQuantums,proto3,customtype=github.com/dydxprotocol/v4-chain/protocol/dtypes.SerializableInt" json:"min_quote_quantums"` +} + +func (m *MsgWithdrawFromMegavault) Reset() { *m = MsgWithdrawFromMegavault{} } +func (m *MsgWithdrawFromMegavault) String() string { return proto.CompactTextString(m) } +func (*MsgWithdrawFromMegavault) ProtoMessage() {} +func (*MsgWithdrawFromMegavault) Descriptor() ([]byte, []int) { + return fileDescriptor_ced574c6017ce006, []int{2} +} +func (m *MsgWithdrawFromMegavault) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgWithdrawFromMegavault) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgWithdrawFromMegavault.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 *MsgWithdrawFromMegavault) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgWithdrawFromMegavault.Merge(m, src) +} +func (m *MsgWithdrawFromMegavault) XXX_Size() int { + return m.Size() +} +func (m *MsgWithdrawFromMegavault) XXX_DiscardUnknown() { + xxx_messageInfo_MsgWithdrawFromMegavault.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgWithdrawFromMegavault proto.InternalMessageInfo + +func (m *MsgWithdrawFromMegavault) GetSubaccountId() types.SubaccountId { + if m != nil { + return m.SubaccountId + } + return types.SubaccountId{} +} + +func (m *MsgWithdrawFromMegavault) GetShares() NumShares { + if m != nil { + return m.Shares + } + return NumShares{} +} + +// MsgWithdrawFromMegavaultResponse is the Msg/WithdrawFromMegavault response +// type. +type MsgWithdrawFromMegavaultResponse struct { + // The number of quote quantums redeemed from the withdrawal. + QuoteQuantums github_com_dydxprotocol_v4_chain_protocol_dtypes.SerializableInt `protobuf:"bytes,1,opt,name=quote_quantums,json=quoteQuantums,proto3,customtype=github.com/dydxprotocol/v4-chain/protocol/dtypes.SerializableInt" json:"quote_quantums"` +} + +func (m *MsgWithdrawFromMegavaultResponse) Reset() { *m = MsgWithdrawFromMegavaultResponse{} } +func (m *MsgWithdrawFromMegavaultResponse) String() string { return proto.CompactTextString(m) } +func (*MsgWithdrawFromMegavaultResponse) ProtoMessage() {} +func (*MsgWithdrawFromMegavaultResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_ced574c6017ce006, []int{3} +} +func (m *MsgWithdrawFromMegavaultResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgWithdrawFromMegavaultResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgWithdrawFromMegavaultResponse.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 *MsgWithdrawFromMegavaultResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgWithdrawFromMegavaultResponse.Merge(m, src) +} +func (m *MsgWithdrawFromMegavaultResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgWithdrawFromMegavaultResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgWithdrawFromMegavaultResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgWithdrawFromMegavaultResponse proto.InternalMessageInfo + // MsgUpdateDefaultQuotingParams is the Msg/UpdateDefaultQuotingParams request // type. type MsgUpdateDefaultQuotingParams struct { @@ -139,7 +238,7 @@ func (m *MsgUpdateDefaultQuotingParams) Reset() { *m = MsgUpdateDefaultQ func (m *MsgUpdateDefaultQuotingParams) String() string { return proto.CompactTextString(m) } func (*MsgUpdateDefaultQuotingParams) ProtoMessage() {} func (*MsgUpdateDefaultQuotingParams) Descriptor() ([]byte, []int) { - return fileDescriptor_ced574c6017ce006, []int{2} + return fileDescriptor_ced574c6017ce006, []int{4} } func (m *MsgUpdateDefaultQuotingParams) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -191,7 +290,7 @@ func (m *MsgUpdateDefaultQuotingParamsResponse) Reset() { *m = MsgUpdate func (m *MsgUpdateDefaultQuotingParamsResponse) String() string { return proto.CompactTextString(m) } func (*MsgUpdateDefaultQuotingParamsResponse) ProtoMessage() {} func (*MsgUpdateDefaultQuotingParamsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ced574c6017ce006, []int{3} + return fileDescriptor_ced574c6017ce006, []int{5} } func (m *MsgUpdateDefaultQuotingParamsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -233,7 +332,7 @@ func (m *MsgSetVaultParams) Reset() { *m = MsgSetVaultParams{} } func (m *MsgSetVaultParams) String() string { return proto.CompactTextString(m) } func (*MsgSetVaultParams) ProtoMessage() {} func (*MsgSetVaultParams) Descriptor() ([]byte, []int) { - return fileDescriptor_ced574c6017ce006, []int{4} + return fileDescriptor_ced574c6017ce006, []int{6} } func (m *MsgSetVaultParams) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -291,7 +390,7 @@ func (m *MsgSetVaultParamsResponse) Reset() { *m = MsgSetVaultParamsResp func (m *MsgSetVaultParamsResponse) String() string { return proto.CompactTextString(m) } func (*MsgSetVaultParamsResponse) ProtoMessage() {} func (*MsgSetVaultParamsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ced574c6017ce006, []int{5} + return fileDescriptor_ced574c6017ce006, []int{7} } func (m *MsgSetVaultParamsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -331,7 +430,7 @@ func (m *MsgUnlockShares) Reset() { *m = MsgUnlockShares{} } func (m *MsgUnlockShares) String() string { return proto.CompactTextString(m) } func (*MsgUnlockShares) ProtoMessage() {} func (*MsgUnlockShares) Descriptor() ([]byte, []int) { - return fileDescriptor_ced574c6017ce006, []int{6} + return fileDescriptor_ced574c6017ce006, []int{8} } func (m *MsgUnlockShares) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -384,7 +483,7 @@ func (m *MsgUnlockSharesResponse) Reset() { *m = MsgUnlockSharesResponse func (m *MsgUnlockSharesResponse) String() string { return proto.CompactTextString(m) } func (*MsgUnlockSharesResponse) ProtoMessage() {} func (*MsgUnlockSharesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ced574c6017ce006, []int{7} + return fileDescriptor_ced574c6017ce006, []int{9} } func (m *MsgUnlockSharesResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -434,7 +533,7 @@ func (m *MsgUpdateParams) Reset() { *m = MsgUpdateParams{} } func (m *MsgUpdateParams) String() string { return proto.CompactTextString(m) } func (*MsgUpdateParams) ProtoMessage() {} func (*MsgUpdateParams) Descriptor() ([]byte, []int) { - return fileDescriptor_ced574c6017ce006, []int{8} + return fileDescriptor_ced574c6017ce006, []int{10} } func (m *MsgUpdateParams) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -488,7 +587,7 @@ func (m *MsgUpdateOperatorParams) Reset() { *m = MsgUpdateOperatorParams func (m *MsgUpdateOperatorParams) String() string { return proto.CompactTextString(m) } func (*MsgUpdateOperatorParams) ProtoMessage() {} func (*MsgUpdateOperatorParams) Descriptor() ([]byte, []int) { - return fileDescriptor_ced574c6017ce006, []int{9} + return fileDescriptor_ced574c6017ce006, []int{11} } func (m *MsgUpdateOperatorParams) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -539,7 +638,7 @@ func (m *MsgUpdateOperatorParamsResponse) Reset() { *m = MsgUpdateOperat func (m *MsgUpdateOperatorParamsResponse) String() string { return proto.CompactTextString(m) } func (*MsgUpdateOperatorParamsResponse) ProtoMessage() {} func (*MsgUpdateOperatorParamsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ced574c6017ce006, []int{10} + return fileDescriptor_ced574c6017ce006, []int{12} } func (m *MsgUpdateOperatorParamsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -581,7 +680,7 @@ func (m *MsgAllocateToVault) Reset() { *m = MsgAllocateToVault{} } func (m *MsgAllocateToVault) String() string { return proto.CompactTextString(m) } func (*MsgAllocateToVault) ProtoMessage() {} func (*MsgAllocateToVault) Descriptor() ([]byte, []int) { - return fileDescriptor_ced574c6017ce006, []int{11} + return fileDescriptor_ced574c6017ce006, []int{13} } func (m *MsgAllocateToVault) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -632,7 +731,7 @@ func (m *MsgAllocateToVaultResponse) Reset() { *m = MsgAllocateToVaultRe func (m *MsgAllocateToVaultResponse) String() string { return proto.CompactTextString(m) } func (*MsgAllocateToVaultResponse) ProtoMessage() {} func (*MsgAllocateToVaultResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ced574c6017ce006, []int{12} + return fileDescriptor_ced574c6017ce006, []int{14} } func (m *MsgAllocateToVaultResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -664,6 +763,8 @@ var xxx_messageInfo_MsgAllocateToVaultResponse proto.InternalMessageInfo func init() { proto.RegisterType((*MsgDepositToMegavault)(nil), "dydxprotocol.vault.MsgDepositToMegavault") proto.RegisterType((*MsgDepositToMegavaultResponse)(nil), "dydxprotocol.vault.MsgDepositToMegavaultResponse") + proto.RegisterType((*MsgWithdrawFromMegavault)(nil), "dydxprotocol.vault.MsgWithdrawFromMegavault") + proto.RegisterType((*MsgWithdrawFromMegavaultResponse)(nil), "dydxprotocol.vault.MsgWithdrawFromMegavaultResponse") proto.RegisterType((*MsgUpdateDefaultQuotingParams)(nil), "dydxprotocol.vault.MsgUpdateDefaultQuotingParams") proto.RegisterType((*MsgUpdateDefaultQuotingParamsResponse)(nil), "dydxprotocol.vault.MsgUpdateDefaultQuotingParamsResponse") proto.RegisterType((*MsgSetVaultParams)(nil), "dydxprotocol.vault.MsgSetVaultParams") @@ -680,60 +781,65 @@ func init() { func init() { proto.RegisterFile("dydxprotocol/vault/tx.proto", fileDescriptor_ced574c6017ce006) } var fileDescriptor_ced574c6017ce006 = []byte{ - // 834 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x56, 0x4f, 0x4f, 0x13, 0x4d, - 0x18, 0xef, 0xc2, 0xfb, 0xf2, 0xbe, 0x0c, 0x6d, 0xd1, 0x4d, 0x95, 0xb2, 0x48, 0x0b, 0x25, 0x20, - 0x48, 0xd8, 0x06, 0x30, 0xfe, 0x21, 0x1e, 0xa0, 0xe1, 0x00, 0xd1, 0xaa, 0xb4, 0xe8, 0xc1, 0xc4, - 0xd4, 0xe9, 0xee, 0xb0, 0xdd, 0xd8, 0xee, 0x94, 0x9d, 0xd9, 0x5a, 0x3c, 0x78, 0xf0, 0xa8, 0x17, - 0x2f, 0x7e, 0x02, 0xbf, 0x80, 0x07, 0xfd, 0x0a, 0x86, 0x23, 0xf1, 0x64, 0x3c, 0x10, 0x43, 0x0f, - 0xc6, 0x6f, 0x61, 0x76, 0x66, 0xbb, 0xed, 0x6e, 0xb7, 0x4d, 0x81, 0x18, 0x2f, 0xb0, 0xfb, 0xcc, - 0xef, 0x79, 0x9e, 0xdf, 0xef, 0x37, 0xcf, 0xcc, 0x16, 0x4c, 0xa8, 0x07, 0x6a, 0xbd, 0x6a, 0x62, - 0x8a, 0x15, 0x5c, 0x4e, 0xd7, 0xa0, 0x55, 0xa6, 0x69, 0x5a, 0x97, 0x59, 0x44, 0x14, 0xdb, 0x17, - 0x65, 0xb6, 0x28, 0x8d, 0x2b, 0x98, 0x54, 0x30, 0x29, 0xb0, 0x70, 0x9a, 0xbf, 0x70, 0xb8, 0x34, - 0xc6, 0xdf, 0xd2, 0x15, 0xa2, 0xa5, 0x6b, 0xcb, 0xf6, 0x3f, 0x67, 0x61, 0xc1, 0xd3, 0x84, 0x58, - 0x45, 0xa8, 0x28, 0xd8, 0x32, 0x28, 0x69, 0x7b, 0x76, 0xa0, 0xc9, 0x00, 0x3e, 0x55, 0x68, 0xc2, - 0x4a, 0xb3, 0x49, 0x22, 0x00, 0x40, 0x4a, 0xd0, 0x44, 0x3d, 0xd6, 0xd9, 0x5f, 0x67, 0x3d, 0xa6, - 0x61, 0x0d, 0x73, 0xf2, 0xf6, 0x13, 0x8f, 0xa6, 0x7e, 0x09, 0xe0, 0x52, 0x96, 0x68, 0x9b, 0xa8, - 0x8a, 0x89, 0x4e, 0x77, 0x71, 0x16, 0x69, 0x90, 0x65, 0x89, 0x77, 0x41, 0xa4, 0x45, 0xb2, 0xa0, - 0xab, 0x71, 0x61, 0x4a, 0x98, 0x1f, 0x59, 0x99, 0x93, 0x3d, 0xde, 0xb4, 0x69, 0x92, 0xf3, 0xee, - 0xf3, 0xb6, 0x9a, 0x0b, 0x93, 0xb6, 0x37, 0x11, 0x83, 0xe8, 0xbe, 0x85, 0x29, 0x2a, 0xec, 0x5b, - 0xd0, 0xa0, 0x56, 0x85, 0xc4, 0x07, 0xa6, 0x84, 0xf9, 0x70, 0x66, 0xeb, 0xf0, 0x38, 0x19, 0xfa, - 0x7e, 0x9c, 0x5c, 0xd7, 0x74, 0x5a, 0xb2, 0x8a, 0xb2, 0x82, 0x2b, 0x69, 0xaf, 0x8e, 0xeb, 0x4b, - 0x4a, 0x09, 0xea, 0x46, 0xda, 0x8d, 0xa8, 0xf4, 0xa0, 0x8a, 0x88, 0x9c, 0x47, 0xa6, 0x0e, 0xcb, - 0xfa, 0x4b, 0x58, 0x2c, 0xa3, 0x6d, 0x83, 0xe6, 0x22, 0xac, 0xfe, 0x8e, 0x53, 0x7e, 0x4d, 0x7c, - 0xfd, 0xf3, 0xe3, 0x35, 0xaf, 0x80, 0x94, 0x0e, 0x26, 0x03, 0xa5, 0xe6, 0x10, 0xa9, 0x62, 0x83, - 0x20, 0x71, 0x0b, 0x44, 0x2a, 0xba, 0x41, 0x91, 0x5a, 0x60, 0xc6, 0x12, 0x47, 0xf2, 0xa4, 0xdc, - 0x39, 0x0e, 0xf2, 0x7d, 0xab, 0x92, 0x67, 0xa0, 0xcc, 0x3f, 0xb6, 0x86, 0x5c, 0x98, 0x67, 0xf2, - 0x58, 0xea, 0x8b, 0xc0, 0x7a, 0x3d, 0xaa, 0xaa, 0x90, 0xa2, 0x4d, 0xb4, 0x67, 0xa7, 0xec, 0x58, - 0x98, 0xea, 0x86, 0xf6, 0x90, 0x6d, 0xaa, 0x78, 0x03, 0x0c, 0x43, 0x8b, 0x96, 0xb0, 0xa9, 0xd3, - 0x03, 0xd6, 0x67, 0x38, 0x13, 0xff, 0xfa, 0x69, 0x29, 0xe6, 0x0c, 0xd6, 0x86, 0xaa, 0x9a, 0x88, - 0x90, 0x3c, 0x35, 0x75, 0x43, 0xcb, 0xb5, 0xa0, 0xe2, 0x53, 0x70, 0x59, 0xe5, 0xf5, 0x0a, 0xfb, - 0xbc, 0x60, 0x81, 0x8f, 0x09, 0x73, 0x74, 0x64, 0x65, 0x3a, 0x88, 0xac, 0xa7, 0xb5, 0x43, 0x38, - 0xa6, 0x06, 0xd0, 0x5a, 0x8b, 0xda, 0xbe, 0xb5, 0xda, 0xa5, 0xae, 0x82, 0xd9, 0x9e, 0x3a, 0x9a, - 0xde, 0xa5, 0x1a, 0x02, 0xb8, 0x98, 0x25, 0x5a, 0x1e, 0xd1, 0xc7, 0x36, 0xe8, 0x9c, 0x2a, 0xef, - 0x80, 0xff, 0x19, 0x73, 0x7b, 0xee, 0xb8, 0xae, 0x89, 0x20, 0x5d, 0xac, 0xd5, 0xb6, 0xea, 0x28, - 0xfa, 0xaf, 0xc6, 0x5f, 0xc5, 0x2d, 0x10, 0xe6, 0xd9, 0x8e, 0x33, 0x83, 0xac, 0x42, 0xb2, 0x6b, - 0x05, 0x8f, 0x2f, 0x23, 0xb5, 0x56, 0xa8, 0xc3, 0x8e, 0x09, 0x30, 0xde, 0x21, 0xd2, 0xb5, 0xe0, - 0x15, 0x18, 0xb5, 0xbd, 0x32, 0xca, 0x58, 0x79, 0xce, 0xe7, 0xe0, 0xcc, 0xfa, 0x67, 0x40, 0x04, - 0xbf, 0x30, 0x90, 0x59, 0x80, 0x1c, 0xc1, 0x4c, 0x18, 0xce, 0x85, 0x59, 0xd0, 0xc9, 0xea, 0x20, - 0xa7, 0x81, 0x31, 0x5f, 0x7f, 0x77, 0xb2, 0xef, 0x81, 0x51, 0x8b, 0xc5, 0xcf, 0x34, 0xdb, 0xd1, - 0x66, 0xae, 0x33, 0xdd, 0xef, 0x05, 0xae, 0x94, 0x4d, 0xc5, 0x39, 0x77, 0xfa, 0x16, 0x18, 0xf2, - 0xcc, 0xaf, 0x14, 0x44, 0xc8, 0xb3, 0x41, 0x0e, 0x7e, 0xed, 0x82, 0x57, 0x7e, 0x5c, 0x48, 0x7d, - 0x10, 0xb8, 0x03, 0x8c, 0xd7, 0x83, 0x2a, 0x32, 0x21, 0xc5, 0xe6, 0x39, 0xf9, 0xad, 0xfb, 0xf8, - 0xa5, 0x82, 0xf8, 0x79, 0x7b, 0xf9, 0x78, 0xfa, 0xb7, 0x69, 0x1a, 0x24, 0xbb, 0x90, 0x74, 0x27, - 0xe9, 0xed, 0x00, 0x10, 0xb3, 0x44, 0xdb, 0x28, 0x97, 0xb1, 0x02, 0x29, 0xda, 0xc5, 0x6c, 0xdc, - 0xfe, 0xd2, 0x69, 0xea, 0xbc, 0xbb, 0x07, 0xff, 0xec, 0xdd, 0xed, 0x37, 0xec, 0x0a, 0x90, 0x3a, - 0xcd, 0x68, 0x7a, 0xb5, 0xf2, 0xf9, 0x5f, 0x30, 0x98, 0x25, 0x9a, 0x68, 0x02, 0x31, 0xe0, 0x2b, - 0xb6, 0x10, 0x24, 0x34, 0xf0, 0x2b, 0x20, 0x2d, 0xf7, 0x0d, 0x75, 0x8f, 0xd5, 0x1b, 0x01, 0x48, - 0x3d, 0xee, 0xf8, 0x6e, 0x15, 0xbb, 0xa7, 0x48, 0xb7, 0x4f, 0x9d, 0xe2, 0x92, 0xa9, 0x83, 0x58, - 0xe0, 0xe4, 0x2f, 0xf6, 0x2c, 0xe9, 0x05, 0x4b, 0xab, 0xa7, 0x00, 0xbb, 0x9d, 0xf7, 0x40, 0xd4, - 0x77, 0xef, 0xcf, 0x76, 0x29, 0xe3, 0x85, 0x49, 0x4b, 0x7d, 0xc1, 0xdc, 0x3e, 0xcf, 0x40, 0xd8, - 0x73, 0xbb, 0xce, 0x74, 0x23, 0xdb, 0x06, 0x92, 0x16, 0xfb, 0x00, 0xb9, 0x1d, 0x74, 0x30, 0xea, - 0x3f, 0x74, 0x73, 0x5d, 0xf2, 0x7d, 0x38, 0x49, 0xee, 0x0f, 0xd7, 0x6c, 0x95, 0xd9, 0x39, 0x3c, - 0x49, 0x08, 0x47, 0x27, 0x09, 0xe1, 0xc7, 0x49, 0x42, 0x78, 0xd7, 0x48, 0x84, 0x8e, 0x1a, 0x89, - 0xd0, 0xb7, 0x46, 0x22, 0xf4, 0xe4, 0x66, 0xff, 0x07, 0xaa, 0xde, 0xfc, 0xe5, 0x6a, 0x9f, 0xab, - 0xe2, 0x10, 0x8b, 0xaf, 0xfe, 0x0e, 0x00, 0x00, 0xff, 0xff, 0x36, 0x56, 0xc3, 0xbf, 0xdc, 0x0a, - 0x00, 0x00, + // 928 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x57, 0x4f, 0x8f, 0xdb, 0x44, + 0x14, 0x5f, 0xef, 0xa2, 0xc0, 0xbe, 0x26, 0xd9, 0x62, 0xa5, 0x34, 0xf5, 0xd2, 0x64, 0xeb, 0xaa, + 0xa5, 0xa5, 0xac, 0xa3, 0xfe, 0x11, 0x7f, 0x16, 0x0e, 0x6d, 0x54, 0xa1, 0xad, 0x20, 0x40, 0x92, + 0x02, 0x12, 0x12, 0x0a, 0x13, 0x7b, 0xea, 0x8c, 0x88, 0x3d, 0xa9, 0x67, 0x9c, 0x66, 0x41, 0xe2, + 0xc0, 0x11, 0x2e, 0x48, 0x88, 0x4f, 0xc0, 0x17, 0x40, 0x08, 0xf1, 0x11, 0x50, 0x8f, 0x15, 0x27, + 0xc4, 0xa1, 0x42, 0x9b, 0x03, 0xe2, 0x5b, 0x20, 0xcf, 0x38, 0x4e, 0xec, 0xd8, 0x21, 0xdb, 0xb0, + 0xea, 0x65, 0xd7, 0xf3, 0xe6, 0xf7, 0xe6, 0xfd, 0xde, 0xef, 0xbd, 0x37, 0xb3, 0x0b, 0xdb, 0xd6, + 0x81, 0x35, 0x1a, 0x78, 0x94, 0x53, 0x93, 0xf6, 0x6b, 0x43, 0xe4, 0xf7, 0x79, 0x8d, 0x8f, 0x0c, + 0x61, 0x51, 0xd5, 0xd9, 0x4d, 0x43, 0x6c, 0x6a, 0x67, 0x4c, 0xca, 0x1c, 0xca, 0x3a, 0xc2, 0x5c, + 0x93, 0x0b, 0x09, 0xd7, 0x4e, 0xcb, 0x55, 0xcd, 0x61, 0x76, 0x6d, 0x78, 0x35, 0xf8, 0x15, 0x6e, + 0x5c, 0x8e, 0x05, 0x61, 0x7e, 0x17, 0x99, 0x26, 0xf5, 0x5d, 0xce, 0x66, 0xbe, 0x43, 0x68, 0x35, + 0x85, 0xcf, 0x00, 0x79, 0xc8, 0x99, 0x04, 0xa9, 0xa4, 0x00, 0x58, 0x0f, 0x79, 0x78, 0xc1, 0xbe, + 0xf8, 0x19, 0xee, 0x97, 0x6c, 0x6a, 0x53, 0x49, 0x3e, 0xf8, 0x92, 0x56, 0xfd, 0x1f, 0x05, 0x4e, + 0x35, 0x98, 0x7d, 0x1b, 0x0f, 0x28, 0x23, 0xfc, 0x2e, 0x6d, 0x60, 0x1b, 0x09, 0x2f, 0xf5, 0x1d, + 0x28, 0x4c, 0x49, 0x76, 0x88, 0x55, 0x56, 0x76, 0x94, 0x4b, 0x27, 0xae, 0x5d, 0x34, 0x62, 0xda, + 0xcc, 0xe4, 0x64, 0xb4, 0xa3, 0xef, 0x3b, 0x56, 0x2b, 0xcf, 0x66, 0x56, 0x2a, 0x85, 0xe2, 0x7d, + 0x9f, 0x72, 0xdc, 0xb9, 0xef, 0x23, 0x97, 0xfb, 0x0e, 0x2b, 0xaf, 0xef, 0x28, 0x97, 0xf2, 0xf5, + 0xfd, 0x87, 0x8f, 0xab, 0x6b, 0x7f, 0x3e, 0xae, 0xde, 0xb4, 0x09, 0xef, 0xf9, 0x5d, 0xc3, 0xa4, + 0x4e, 0x2d, 0x9e, 0xc7, 0x8d, 0x5d, 0xb3, 0x87, 0x88, 0x5b, 0x8b, 0x2c, 0x16, 0x3f, 0x18, 0x60, + 0x66, 0xb4, 0xb1, 0x47, 0x50, 0x9f, 0x7c, 0x81, 0xba, 0x7d, 0x7c, 0xc7, 0xe5, 0xad, 0x82, 0x38, + 0xbf, 0x19, 0x1e, 0xbf, 0xa7, 0x7e, 0xfd, 0xf7, 0x4f, 0x2f, 0xc7, 0x13, 0xd0, 0x09, 0x9c, 0x4d, + 0x4d, 0xb5, 0x85, 0xd9, 0x80, 0xba, 0x0c, 0xab, 0xfb, 0x50, 0x70, 0x88, 0xcb, 0xb1, 0xd5, 0x11, + 0xc2, 0xb2, 0x30, 0xe5, 0xb3, 0xc6, 0x7c, 0x3b, 0x18, 0xef, 0xf9, 0x4e, 0x5b, 0x80, 0xea, 0xcf, + 0x04, 0x39, 0xb4, 0xf2, 0xd2, 0x53, 0xda, 0xf4, 0x5f, 0xd7, 0xa1, 0xdc, 0x60, 0xf6, 0xc7, 0x84, + 0xf7, 0x2c, 0x0f, 0x3d, 0x78, 0xdb, 0xa3, 0xce, 0x54, 0xd9, 0xe6, 0x4a, 0xca, 0x4e, 0xe2, 0xc5, + 0xf4, 0x7d, 0x13, 0x72, 0x21, 0xe5, 0xf5, 0xe5, 0x29, 0x87, 0x2e, 0xea, 0x10, 0x54, 0x87, 0xb8, + 0x9d, 0x44, 0x81, 0x36, 0xfe, 0xe7, 0x02, 0x9d, 0x74, 0x88, 0xdb, 0xfc, 0xcf, 0x1a, 0x7d, 0xaf, + 0xc0, 0x4e, 0x96, 0x70, 0x51, 0x9d, 0xe6, 0xbb, 0x49, 0x39, 0xd6, 0x6e, 0xd2, 0x7f, 0x53, 0x44, + 0xeb, 0x7c, 0x38, 0xb0, 0x10, 0xc7, 0xb7, 0xf1, 0xbd, 0x80, 0x4d, 0x90, 0x0b, 0x71, 0xed, 0x0f, + 0xc4, 0x8c, 0xaa, 0xaf, 0xc2, 0x26, 0xf2, 0x79, 0x8f, 0x7a, 0x84, 0x1f, 0x08, 0x36, 0x9b, 0xf5, + 0xf2, 0xef, 0xbf, 0xec, 0x96, 0xc2, 0x7b, 0xe2, 0x96, 0x65, 0x79, 0x98, 0xb1, 0x36, 0xf7, 0x88, + 0x6b, 0xb7, 0xa6, 0x50, 0xf5, 0x53, 0x78, 0xc1, 0x92, 0xe7, 0x09, 0xfd, 0x89, 0x6b, 0x77, 0xe4, + 0xd4, 0x87, 0x85, 0x3c, 0x97, 0x56, 0xc8, 0x58, 0xe8, 0xb0, 0x98, 0x25, 0x2b, 0x85, 0xd6, 0x5e, + 0x31, 0x90, 0x78, 0x1a, 0x4e, 0x7f, 0x09, 0x2e, 0x2c, 0xcc, 0x63, 0x22, 0xb1, 0x3e, 0x56, 0xe0, + 0xf9, 0x06, 0xb3, 0xdb, 0x98, 0x7f, 0x14, 0x80, 0x56, 0xcc, 0xf2, 0x2d, 0x78, 0x4e, 0x30, 0x0f, + 0x9a, 0x5d, 0xe6, 0xb5, 0x9d, 0x96, 0x97, 0x08, 0x15, 0x75, 0xf8, 0xb3, 0x43, 0xb9, 0x54, 0xf7, + 0x21, 0x2f, 0xbd, 0x43, 0x65, 0x36, 0xc4, 0x09, 0xd5, 0xcc, 0x13, 0x62, 0xba, 0x9c, 0x18, 0x4e, + 0x4d, 0x73, 0x72, 0x6c, 0xc3, 0x99, 0xb9, 0x24, 0x23, 0x09, 0xbe, 0x82, 0xad, 0x40, 0x2b, 0xb7, + 0x4f, 0xcd, 0xcf, 0xe5, 0xdc, 0x3c, 0x71, 0xfe, 0xe7, 0xa1, 0x40, 0x1f, 0xb8, 0xd8, 0xeb, 0x20, + 0x89, 0x10, 0x22, 0x6c, 0xb6, 0xf2, 0xc2, 0x18, 0x7a, 0xcd, 0x91, 0xb3, 0xe1, 0x74, 0x22, 0x7e, + 0x34, 0x00, 0xef, 0xc2, 0x96, 0x2f, 0xec, 0x4f, 0x74, 0x55, 0x15, 0x27, 0xbe, 0xe1, 0x65, 0xf5, + 0x83, 0x22, 0x33, 0x15, 0x5d, 0xb1, 0x62, 0xa5, 0x5f, 0x87, 0x5c, 0xac, 0x7f, 0xb5, 0x34, 0x42, + 0xb1, 0x02, 0x85, 0xf8, 0xbd, 0x93, 0xf1, 0xf4, 0xcb, 0x8a, 0xfe, 0xa3, 0x22, 0x15, 0x10, 0xbc, + 0xde, 0x1f, 0x60, 0x0f, 0x71, 0xea, 0xad, 0xc8, 0xef, 0x66, 0x82, 0x9f, 0x9e, 0xc6, 0x2f, 0x1e, + 0x2b, 0xc1, 0x33, 0x59, 0xa6, 0x73, 0x50, 0xcd, 0x20, 0x19, 0x75, 0xd2, 0xb7, 0xeb, 0xa0, 0x36, + 0x98, 0x7d, 0xab, 0xdf, 0xa7, 0x26, 0xe2, 0xf8, 0x2e, 0x15, 0xed, 0xf6, 0x94, 0xa6, 0x69, 0xfe, + 0xf2, 0xdc, 0x38, 0xde, 0xa7, 0x38, 0x29, 0xd8, 0x8b, 0xa0, 0xcd, 0x8b, 0x31, 0xd1, 0xea, 0xda, + 0xcf, 0x39, 0xd8, 0x68, 0x30, 0x5b, 0xf5, 0x40, 0x4d, 0xf9, 0xa3, 0xe4, 0x72, 0x5a, 0xa2, 0xa9, + 0x8f, 0xba, 0x76, 0x75, 0x69, 0x68, 0x34, 0x56, 0x5f, 0xc2, 0xa9, 0xf4, 0x17, 0xfb, 0x95, 0x8c, + 0xb3, 0x52, 0xd1, 0xda, 0x8d, 0xa3, 0xa0, 0xa3, 0xe0, 0xdf, 0x28, 0xa0, 0x2d, 0x78, 0x60, 0xb2, + 0xd2, 0xc9, 0x76, 0xd1, 0xde, 0x38, 0xb2, 0x4b, 0x44, 0x66, 0x04, 0xa5, 0xd4, 0xb1, 0xbb, 0xb2, + 0xf0, 0xc8, 0x38, 0x58, 0xbb, 0x7e, 0x04, 0x70, 0x14, 0xf9, 0x1e, 0x14, 0x13, 0x8f, 0xce, 0x85, + 0x8c, 0x63, 0xe2, 0x30, 0x6d, 0x77, 0x29, 0x58, 0x14, 0xe7, 0x33, 0xc8, 0xc7, 0xae, 0xf6, 0xf3, + 0x59, 0x64, 0x67, 0x40, 0xda, 0x95, 0x25, 0x40, 0x51, 0x04, 0x02, 0x5b, 0xc9, 0x89, 0xbf, 0x98, + 0xe1, 0x9f, 0xc0, 0x69, 0xc6, 0x72, 0xb8, 0x49, 0xa8, 0x7a, 0xf3, 0xe1, 0x61, 0x45, 0x79, 0x74, + 0x58, 0x51, 0xfe, 0x3a, 0xac, 0x28, 0xdf, 0x8d, 0x2b, 0x6b, 0x8f, 0xc6, 0x95, 0xb5, 0x3f, 0xc6, + 0x95, 0xb5, 0x4f, 0x5e, 0x5b, 0x7e, 0x9a, 0x47, 0x93, 0xff, 0x82, 0x82, 0xa1, 0xee, 0xe6, 0x84, + 0xfd, 0xfa, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xe8, 0x01, 0x50, 0xc1, 0x28, 0x0d, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -750,6 +856,8 @@ const _ = grpc.SupportPackageIsVersion4 type MsgClient interface { // DepositToMegavault deposits funds into megavault. DepositToMegavault(ctx context.Context, in *MsgDepositToMegavault, opts ...grpc.CallOption) (*MsgDepositToMegavaultResponse, error) + // WithdrawFromMegavault withdraws shares from megavault. + WithdrawFromMegavault(ctx context.Context, in *MsgWithdrawFromMegavault, opts ...grpc.CallOption) (*MsgWithdrawFromMegavaultResponse, error) // UpdateDefaultQuotingParams updates the default quoting params in state. UpdateDefaultQuotingParams(ctx context.Context, in *MsgUpdateDefaultQuotingParams, opts ...grpc.CallOption) (*MsgUpdateDefaultQuotingParamsResponse, error) // UpdateOperatorParams sets the parameters regarding megavault operator. @@ -780,6 +888,15 @@ func (c *msgClient) DepositToMegavault(ctx context.Context, in *MsgDepositToMega return out, nil } +func (c *msgClient) WithdrawFromMegavault(ctx context.Context, in *MsgWithdrawFromMegavault, opts ...grpc.CallOption) (*MsgWithdrawFromMegavaultResponse, error) { + out := new(MsgWithdrawFromMegavaultResponse) + err := c.cc.Invoke(ctx, "/dydxprotocol.vault.Msg/WithdrawFromMegavault", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *msgClient) UpdateDefaultQuotingParams(ctx context.Context, in *MsgUpdateDefaultQuotingParams, opts ...grpc.CallOption) (*MsgUpdateDefaultQuotingParamsResponse, error) { out := new(MsgUpdateDefaultQuotingParamsResponse) err := c.cc.Invoke(ctx, "/dydxprotocol.vault.Msg/UpdateDefaultQuotingParams", in, out, opts...) @@ -829,6 +946,8 @@ func (c *msgClient) AllocateToVault(ctx context.Context, in *MsgAllocateToVault, type MsgServer interface { // DepositToMegavault deposits funds into megavault. DepositToMegavault(context.Context, *MsgDepositToMegavault) (*MsgDepositToMegavaultResponse, error) + // WithdrawFromMegavault withdraws shares from megavault. + WithdrawFromMegavault(context.Context, *MsgWithdrawFromMegavault) (*MsgWithdrawFromMegavaultResponse, error) // UpdateDefaultQuotingParams updates the default quoting params in state. UpdateDefaultQuotingParams(context.Context, *MsgUpdateDefaultQuotingParams) (*MsgUpdateDefaultQuotingParamsResponse, error) // UpdateOperatorParams sets the parameters regarding megavault operator. @@ -849,6 +968,9 @@ type UnimplementedMsgServer struct { func (*UnimplementedMsgServer) DepositToMegavault(ctx context.Context, req *MsgDepositToMegavault) (*MsgDepositToMegavaultResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method DepositToMegavault not implemented") } +func (*UnimplementedMsgServer) WithdrawFromMegavault(ctx context.Context, req *MsgWithdrawFromMegavault) (*MsgWithdrawFromMegavaultResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method WithdrawFromMegavault not implemented") +} func (*UnimplementedMsgServer) UpdateDefaultQuotingParams(ctx context.Context, req *MsgUpdateDefaultQuotingParams) (*MsgUpdateDefaultQuotingParamsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method UpdateDefaultQuotingParams not implemented") } @@ -887,6 +1009,24 @@ func _Msg_DepositToMegavault_Handler(srv interface{}, ctx context.Context, dec f return interceptor(ctx, in, info, handler) } +func _Msg_WithdrawFromMegavault_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgWithdrawFromMegavault) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).WithdrawFromMegavault(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/dydxprotocol.vault.Msg/WithdrawFromMegavault", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).WithdrawFromMegavault(ctx, req.(*MsgWithdrawFromMegavault)) + } + return interceptor(ctx, in, info, handler) +} + func _Msg_UpdateDefaultQuotingParams_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(MsgUpdateDefaultQuotingParams) if err := dec(in); err != nil { @@ -985,6 +1125,10 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ MethodName: "DepositToMegavault", Handler: _Msg_DepositToMegavault_Handler, }, + { + MethodName: "WithdrawFromMegavault", + Handler: _Msg_WithdrawFromMegavault_Handler, + }, { MethodName: "UpdateDefaultQuotingParams", Handler: _Msg_UpdateDefaultQuotingParams_Handler, @@ -1088,6 +1232,92 @@ func (m *MsgDepositToMegavaultResponse) MarshalToSizedBuffer(dAtA []byte) (int, return len(dAtA) - i, nil } +func (m *MsgWithdrawFromMegavault) 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 *MsgWithdrawFromMegavault) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgWithdrawFromMegavault) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.MinQuoteQuantums.Size() + i -= size + if _, err := m.MinQuoteQuantums.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + { + size, err := m.Shares.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + { + size, err := m.SubaccountId.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *MsgWithdrawFromMegavaultResponse) 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 *MsgWithdrawFromMegavaultResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgWithdrawFromMegavaultResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.QuoteQuantums.Size() + i -= size + if _, err := m.QuoteQuantums.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func (m *MsgUpdateDefaultQuotingParams) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -1507,6 +1737,32 @@ func (m *MsgDepositToMegavaultResponse) Size() (n int) { return n } +func (m *MsgWithdrawFromMegavault) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.SubaccountId.Size() + n += 1 + l + sovTx(uint64(l)) + l = m.Shares.Size() + n += 1 + l + sovTx(uint64(l)) + l = m.MinQuoteQuantums.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgWithdrawFromMegavaultResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.QuoteQuantums.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + func (m *MsgUpdateDefaultQuotingParams) Size() (n int) { if m == nil { return 0 @@ -1858,6 +2114,238 @@ func (m *MsgDepositToMegavaultResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *MsgWithdrawFromMegavault) 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 ErrIntOverflowTx + } + 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: MsgWithdrawFromMegavault: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgWithdrawFromMegavault: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SubaccountId", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.SubaccountId.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Shares", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Shares.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MinQuoteQuantums", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MinQuoteQuantums.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgWithdrawFromMegavaultResponse) 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 ErrIntOverflowTx + } + 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: MsgWithdrawFromMegavaultResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgWithdrawFromMegavaultResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field QuoteQuantums", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.QuoteQuantums.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *MsgUpdateDefaultQuotingParams) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0