From 6d2471d4a27cdc13c45ec410f28a0d63280e56ce Mon Sep 17 00:00:00 2001 From: kosegor <30661385+kosegor@users.noreply.github.com> Date: Thu, 20 Jul 2023 19:13:04 -0300 Subject: [PATCH] feat: Metoken main functionality (#2157) * added metoken spec * Update x/metoken/README.md Co-authored-by: Adam Moser <63419657+toteki@users.noreply.github.com> * addressing PR comments * small tweaks * lint * Update x/metoken/README.md Co-authored-by: Adam Moser <63419657+toteki@users.noreply.github.com> * Update x/metoken/README.md Co-authored-by: Adam Moser <63419657+toteki@users.noreply.github.com> * Update x/metoken/README.md Co-authored-by: Adam Moser <63419657+toteki@users.noreply.github.com> * Update x/metoken/README.md Co-authored-by: Adam Moser <63419657+toteki@users.noreply.github.com> * refactored state * fixing fees * adding last changes * lint * change maxWithdraw * lint * claiming interest change * typo * feat: metoken proto and generated files (#3) * fix: gov remove title from messages * chore: comment out dependabot * feat: Adding metoken Genesis Functions and persistence for the state (#10) Co-authored-by: Robert Zaremba * disable dependabot.yml * feature: meToken (#27) Co-authored-by: Adam Moser <63419657+toteki@users.noreply.github.com> Co-authored-by: Robert Zaremba * adding entry for changelog * changing back dependabot.yml * changing back dependabot.yml_2 * changing back dependabot.yml_3 --------- Co-authored-by: Adam Moser <63419657+toteki@users.noreply.github.com> Co-authored-by: Robert Zaremba Co-authored-by: Ebrahim <104380707+EbrahimUmee@users.noreply.github.com> --- CHANGELOG.md | 1 + app/app.go | 75 +- contrib/scripts/mockgen.sh | 3 +- proto/umee/metoken/v1/events.proto | 55 + proto/umee/metoken/v1/genesis.proto | 40 + proto/umee/metoken/v1/metoken.proto | 105 + proto/umee/metoken/v1/query.proto | 98 + proto/umee/metoken/v1/tx.proto | 88 + util/coin/coin.go | 49 + x/leverage/client/tests/tests.go | 1 - x/leverage/keeper/collateral.go | 4 +- x/leverage/keeper/internal_test.go | 3 + x/leverage/keeper/keeper.go | 34 +- x/leverage/keeper/msg_server.go | 2 +- x/metoken/README.md | 480 +++++ x/metoken/client/cli/query.go | 180 ++ x/metoken/client/cli/tx.go | 85 + x/metoken/codec.go | 46 + x/metoken/events.pb.go | 1407 +++++++++++++ x/metoken/expected_keepers.go | 36 + x/metoken/genesis.go | 164 ++ x/metoken/genesis.pb.go | 1169 +++++++++++ x/metoken/genesis_test.go | 167 ++ x/metoken/index.go | 202 ++ x/metoken/index_test.go | 231 +++ x/metoken/keeper/balance.go | 32 + x/metoken/keeper/balance_test.go | 24 + x/metoken/keeper/fee.go | 133 ++ x/metoken/keeper/fee_test.go | 89 + x/metoken/keeper/genesis.go | 39 + x/metoken/keeper/genesis_test.go | 113 ++ x/metoken/keeper/grpc_query.go | 143 ++ x/metoken/keeper/intest/grpc_query_test.go | 282 +++ x/metoken/keeper/intest/keeper_test.go | 138 ++ x/metoken/keeper/intest/msg_server_test.go | 1894 +++++++++++++++++ x/metoken/keeper/keeper.go | 64 + x/metoken/keeper/keys.go | 25 + x/metoken/keeper/metoken.go | 205 ++ x/metoken/keeper/metoken_test.go | 119 ++ x/metoken/keeper/mocks_test.go | 68 + x/metoken/keeper/msg_server.go | 147 ++ x/metoken/keeper/params.go | 23 + x/metoken/keeper/params_test.go | 20 + x/metoken/keeper/price.go | 110 + x/metoken/keeper/price_test.go | 189 ++ x/metoken/keeper/redeem.go | 207 ++ x/metoken/keeper/swap.go | 219 ++ x/metoken/keeper/unit_test.go | 51 + x/metoken/keys.go | 9 + x/metoken/metoken.pb.go | 1420 +++++++++++++ x/metoken/mocks/generate.go | 4 + x/metoken/mocks/keepers.go | 1612 +++++++++++++++ x/metoken/mocks/metoken.go | 198 ++ x/metoken/module/abci.go | 13 + x/metoken/module/module.go | 139 ++ x/metoken/msgs.go | 181 ++ x/metoken/params.go | 9 + x/metoken/params_test.go | 13 + x/metoken/price.go | 103 + x/metoken/query.pb.go | 2136 ++++++++++++++++++++ x/metoken/query.pb.gw.go | 485 +++++ x/metoken/tx.pb.go | 2115 +++++++++++++++++++ 62 files changed, 17472 insertions(+), 24 deletions(-) create mode 100644 proto/umee/metoken/v1/events.proto create mode 100644 proto/umee/metoken/v1/genesis.proto create mode 100644 proto/umee/metoken/v1/metoken.proto create mode 100644 proto/umee/metoken/v1/query.proto create mode 100644 proto/umee/metoken/v1/tx.proto create mode 100644 x/metoken/README.md create mode 100644 x/metoken/client/cli/query.go create mode 100644 x/metoken/client/cli/tx.go create mode 100644 x/metoken/codec.go create mode 100644 x/metoken/events.pb.go create mode 100644 x/metoken/expected_keepers.go create mode 100644 x/metoken/genesis.go create mode 100644 x/metoken/genesis.pb.go create mode 100644 x/metoken/genesis_test.go create mode 100644 x/metoken/index.go create mode 100644 x/metoken/index_test.go create mode 100644 x/metoken/keeper/balance.go create mode 100644 x/metoken/keeper/balance_test.go create mode 100644 x/metoken/keeper/fee.go create mode 100644 x/metoken/keeper/fee_test.go create mode 100644 x/metoken/keeper/genesis.go create mode 100644 x/metoken/keeper/genesis_test.go create mode 100644 x/metoken/keeper/grpc_query.go create mode 100644 x/metoken/keeper/intest/grpc_query_test.go create mode 100644 x/metoken/keeper/intest/keeper_test.go create mode 100644 x/metoken/keeper/intest/msg_server_test.go create mode 100644 x/metoken/keeper/keeper.go create mode 100644 x/metoken/keeper/keys.go create mode 100644 x/metoken/keeper/metoken.go create mode 100644 x/metoken/keeper/metoken_test.go create mode 100644 x/metoken/keeper/mocks_test.go create mode 100644 x/metoken/keeper/msg_server.go create mode 100644 x/metoken/keeper/params.go create mode 100644 x/metoken/keeper/params_test.go create mode 100644 x/metoken/keeper/price.go create mode 100644 x/metoken/keeper/price_test.go create mode 100644 x/metoken/keeper/redeem.go create mode 100644 x/metoken/keeper/swap.go create mode 100644 x/metoken/keeper/unit_test.go create mode 100644 x/metoken/keys.go create mode 100644 x/metoken/metoken.pb.go create mode 100644 x/metoken/mocks/generate.go create mode 100644 x/metoken/mocks/keepers.go create mode 100644 x/metoken/mocks/metoken.go create mode 100644 x/metoken/module/abci.go create mode 100644 x/metoken/module/module.go create mode 100644 x/metoken/msgs.go create mode 100644 x/metoken/params.go create mode 100644 x/metoken/params_test.go create mode 100644 x/metoken/price.go create mode 100644 x/metoken/query.pb.go create mode 100644 x/metoken/query.pb.gw.go create mode 100644 x/metoken/tx.pb.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a6791eb14..a883a72f31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,6 +55,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ - [2129](https://github.com/umee-network/umee/pull/2129) Emergency Group x/ugov proto. - [2146](https://github.com/umee-network/umee/pull/2146) Add store GetTimeMs and SetTimeMs. +- [2157](https://github.com/umee-network/umee/pull/2157) Add `x/metoken` module. ### Improvements diff --git a/app/app.go b/app/app.go index 96bf1f145e..4a99441541 100644 --- a/app/app.go +++ b/app/app.go @@ -143,6 +143,10 @@ import ( uibcoracle "github.com/umee-network/umee/v5/x/uibc/oracle" uibcquota "github.com/umee-network/umee/v5/x/uibc/quota" uibcquotakeeper "github.com/umee-network/umee/v5/x/uibc/quota/keeper" + + "github.com/umee-network/umee/v5/x/metoken" + metokenkeeper "github.com/umee-network/umee/v5/x/metoken/keeper" + metokenmodule "github.com/umee-network/umee/v5/x/metoken/module" ) var ( @@ -193,6 +197,7 @@ func init() { ugovmodule.AppModuleBasic{}, wasm.AppModuleBasic{}, incentivemodule.AppModuleBasic{}, + metokenmodule.AppModuleBasic{}, } ModuleBasics = module.NewBasicManager(moduleBasics...) @@ -216,6 +221,7 @@ func init() { oracletypes.ModuleName: nil, uibc.ModuleName: nil, ugov.ModuleName: nil, + metoken.ModuleName: {authtypes.Minter, authtypes.Burner}, } } @@ -264,6 +270,7 @@ type UmeeApp struct { bech32IbcKeeper bech32ibckeeper.Keeper UIbcQuotaKeeperB uibcquotakeeper.Builder UGovKeeperB ugovkeeper.Builder + MetokenKeeperB metokenkeeper.Builder // make scoped keepers public for testing purposes ScopedIBCKeeper capabilitykeeper.ScopedKeeper @@ -328,6 +335,7 @@ func New( bech32ibctypes.StoreKey, uibc.StoreKey, ugov.StoreKey, wasm.StoreKey, incentive.StoreKey, + metoken.StoreKey, } keys := sdk.NewKVStoreKeys(storeKeys...) @@ -395,7 +403,11 @@ func New( app.ModuleAccountAddrs(), ) _stakingKeeper := stakingkeeper.NewKeeper( - appCodec, keys[stakingtypes.StoreKey], app.AccountKeeper, app.BankKeeper, app.GetSubspace(stakingtypes.ModuleName), + appCodec, + keys[stakingtypes.StoreKey], + app.AccountKeeper, + app.BankKeeper, + app.GetSubspace(stakingtypes.ModuleName), ) app.StakingKeeper = &_stakingKeeper app.MintKeeper = mintkeeper.NewKeeper( @@ -461,6 +473,7 @@ func New( app.BankKeeper, app.OracleKeeper, cast.ToBool(appOpts.Get(leveragetypes.FlagEnableLiquidatorQuery)), + authtypes.NewModuleAddress(metoken.ModuleName), ) app.LeverageKeeper.SetTokenHooks(app.OracleKeeper.Hooks()) @@ -528,6 +541,14 @@ func New( app.AccountKeeper, app.BankKeeper, app.ScopedTransferKeeper, ) + app.MetokenKeeperB = metokenkeeper.NewKeeperBuilder( + appCodec, + keys[metoken.StoreKey], + app.BankKeeper, + app.LeverageKeeper, + app.OracleKeeper, + ) + // Create Transfer Stack // SendPacket, originates from the application to an IBC channel: // transferKeeper.SendPacket -> uibcquota.SendPacket -> channel.SendPacket @@ -665,7 +686,13 @@ func New( bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper), capability.NewAppModule(appCodec, *app.CapabilityKeeper), crisis.NewAppModule(&app.CrisisKeeper, skipGenesisInvariants), - feegrantmodule.NewAppModule(appCodec, app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper, app.interfaceRegistry), + feegrantmodule.NewAppModule( + appCodec, + app.AccountKeeper, + app.BankKeeper, + app.FeeGrantKeeper, + app.interfaceRegistry, + ), gov.NewAppModule(appCodec, app.GovKeeper, app.AccountKeeper, app.BankKeeper), mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper, nil), // need to dereference StakingKeeper because x/distribution uses interface casting :( @@ -691,6 +718,7 @@ func New( ugovmodule.NewAppModule(appCodec, app.UGovKeeperB), wasm.NewAppModule(app.appCodec, &app.WasmKeeper, app.StakingKeeper, app.AccountKeeper, app.BankKeeper), incentivemodule.NewAppModule(appCodec, app.IncentiveKeeper, app.BankKeeper, app.LeverageKeeper), + metokenmodule.NewAppModule(appCodec, app.MetokenKeeperB), } app.mm = module.NewManager(appModules...) @@ -701,14 +729,26 @@ func New( // NOTE: staking module is required if HistoricalEntries param > 0 // NOTE: capability module's beginblocker must come before any modules using capabilities (e.g. IBC) beginBlockers := []string{ - upgradetypes.ModuleName, capabilitytypes.ModuleName, minttypes.ModuleName, distrtypes.ModuleName, - slashingtypes.ModuleName, evidencetypes.ModuleName, stakingtypes.ModuleName, - ibchost.ModuleName, ibctransfertypes.ModuleName, - authtypes.ModuleName, banktypes.ModuleName, govtypes.ModuleName, crisistypes.ModuleName, genutiltypes.ModuleName, - authz.ModuleName, feegrant.ModuleName, + upgradetypes.ModuleName, + capabilitytypes.ModuleName, + minttypes.ModuleName, + distrtypes.ModuleName, + slashingtypes.ModuleName, + evidencetypes.ModuleName, + stakingtypes.ModuleName, + ibchost.ModuleName, + ibctransfertypes.ModuleName, + authtypes.ModuleName, + banktypes.ModuleName, + govtypes.ModuleName, + crisistypes.ModuleName, + genutiltypes.ModuleName, + authz.ModuleName, + feegrant.ModuleName, nft.ModuleName, group.ModuleName, - paramstypes.ModuleName, vestingtypes.ModuleName, + paramstypes.ModuleName, + vestingtypes.ModuleName, icatypes.ModuleName, // ibcfeetypes.ModuleName, leveragetypes.ModuleName, oracletypes.ModuleName, @@ -717,6 +757,7 @@ func New( ugov.ModuleName, wasm.ModuleName, incentive.ModuleName, + metoken.ModuleName, } endBlockers := []string{ @@ -736,6 +777,7 @@ func New( ugov.ModuleName, wasm.ModuleName, incentive.ModuleName, + metoken.ModuleName, } // NOTE: The genutils module must occur after staking so that pools are @@ -760,6 +802,7 @@ func New( ugov.ModuleName, wasm.ModuleName, incentive.ModuleName, + metoken.ModuleName, } orderMigrations := []string{ @@ -777,6 +820,7 @@ func New( ugov.ModuleName, wasm.ModuleName, incentive.ModuleName, + metoken.ModuleName, } app.mm.SetOrderBeginBlockers(beginBlockers...) @@ -809,8 +853,10 @@ func New( }, ) // TODO: Ensure x/leverage, x/incentive implement simulator and add it here: - simTestModules := genmap.Pick(simStateModules, - []string{oracletypes.ModuleName, ibchost.ModuleName}) + simTestModules := genmap.Pick( + simStateModules, + []string{oracletypes.ModuleName, ibchost.ModuleName}, + ) app.StateSimulationManager = module.NewSimulationManagerFromAppModules(simStateModules, overrideModules) app.sm = module.NewSimulationManagerFromAppModules(simTestModules, nil) @@ -844,7 +890,8 @@ func New( if manager := app.SnapshotManager(); manager != nil { err := manager.RegisterExtensions( - wasmkeeper.NewWasmSnapshotter(app.CommitMultiStore(), &app.WasmKeeper)) + wasmkeeper.NewWasmSnapshotter(app.CommitMultiStore(), &app.WasmKeeper), + ) if err != nil { panic(fmt.Errorf("failed to register snapshot extension: %s", err)) } @@ -865,7 +912,8 @@ func New( return app } -func (app *UmeeApp) setAnteHandler(txConfig client.TxConfig, +func (app *UmeeApp) setAnteHandler( + txConfig client.TxConfig, wasmConfig *wasmtypes.WasmConfig, wasmStoreKey *storetypes.KVStoreKey, ) { anteHandler, err := customante.NewAnteHandler( @@ -879,7 +927,8 @@ func (app *UmeeApp) setAnteHandler(txConfig client.TxConfig, SigGasConsumer: ante.DefaultSigVerificationGasConsumer, WasmConfig: wasmConfig, TXCounterStoreKey: wasmStoreKey, - }) + }, + ) if err != nil { panic(err) } diff --git a/contrib/scripts/mockgen.sh b/contrib/scripts/mockgen.sh index 9ab8c53906..8d7379da1f 100644 --- a/contrib/scripts/mockgen.sh +++ b/contrib/scripts/mockgen.sh @@ -2,4 +2,5 @@ mockgen_cmd="go run github.com/golang/mock/mockgen" -$mockgen_cmd -source ./x/uibc/expected_keepers.go -package mocks -destination ./x/uibc/mocks/keepers.go \ No newline at end of file +$mockgen_cmd -source ./x/uibc/expected_keepers.go -package mocks -destination ./x/uibc/mocks/keepers.go +$mockgen_cmd -source ./x/metoken/expected_keepers.go -package mocks -destination ./x/metoken/mocks/keepers.go \ No newline at end of file diff --git a/proto/umee/metoken/v1/events.proto b/proto/umee/metoken/v1/events.proto new file mode 100644 index 0000000000..40bab9bb86 --- /dev/null +++ b/proto/umee/metoken/v1/events.proto @@ -0,0 +1,55 @@ +syntax = "proto3"; +package umeenetwork.umee.metoken.v1; + +import "gogoproto/gogo.proto"; +import "cosmos_proto/cosmos.proto"; +import "cosmos/base/v1beta1/coin.proto"; + +option go_package = "github.com/umee-network/umee/v5/x/metoken"; + +option (gogoproto.goproto_getters_all) = false; + +// EventSwap is emitted on Msg/Swap +message EventSwap { + // meToken recipient bech32 address. + string recipient = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + // Asset provided for the swap. + cosmos.base.v1beta1.Coin asset = 2 [(gogoproto.nullable) = false]; + // meToken received by the recipient in exchange for the provided asset. + cosmos.base.v1beta1.Coin metoken = 3 [(gogoproto.nullable) = false]; + // Fee provided for the swap. + cosmos.base.v1beta1.Coin fee = 4 [(gogoproto.nullable) = false]; +} + +// EventRedeem is emitted on Msg/Redeem +message EventRedeem { + // Asset recipient bech32 address. + string recipient = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + // meToken provided for the redemption. + cosmos.base.v1beta1.Coin metoken = 2 [(gogoproto.nullable) = false]; + // Asset received by the recipient in exchange for the provided meToken. + cosmos.base.v1beta1.Coin asset = 3 [(gogoproto.nullable) = false]; + // Fee provided for the redemption. + cosmos.base.v1beta1.Coin fee = 4 [(gogoproto.nullable) = false]; +} + +// EventRebalancing is emitted when a reserve re-balancing occurs. +message EventRebalancing { + // RebalancingResults of every asset in every Index. + repeated RebalancingResult results = 1 [(gogoproto.nullable) = false]; +} + +// RebalancingResult of a specific Index with initial and result balances of underlying assets. +message RebalancingResult { + string metoken_denom = 1; + //Initial balance of an asset in the Index before re-balancing. + repeated cosmos.base.v1beta1.Coin initial_balance = 2 [(gogoproto.nullable) = false]; + // Result balance of an asset in the Index after re-balancing. + repeated cosmos.base.v1beta1.Coin result_balance = 3 [(gogoproto.nullable) = false]; +} + +// EventInterestClaim is emitted when the accrued interest was claimed from x/leverage +message EventInterestClaim { + // The denom and amount of successfully claimed interest + repeated cosmos.base.v1beta1.Coin claimed_asset = 1 [(gogoproto.nullable) = false]; +} \ No newline at end of file diff --git a/proto/umee/metoken/v1/genesis.proto b/proto/umee/metoken/v1/genesis.proto new file mode 100644 index 0000000000..b20cb9114d --- /dev/null +++ b/proto/umee/metoken/v1/genesis.proto @@ -0,0 +1,40 @@ +syntax = "proto3"; +package umeenetwork.umee.metoken.v1; + +import "cosmos/base/v1beta1/coin.proto"; +import "gogoproto/gogo.proto"; +import "google/protobuf/timestamp.proto"; +import "umee/metoken/v1/metoken.proto"; + +option go_package = "github.com/umee-network/umee/v5/x/metoken"; + +// GenesisState defines the x/metoken module's genesis state. +message GenesisState { + Params params = 1 [(gogoproto.nullable) = false]; + repeated Index registry = 2 [(gogoproto.nullable) = false]; + repeated IndexBalances balances = 3 [(gogoproto.nullable) = false]; + google.protobuf.Timestamp next_rebalancing_time = 4 [ + (gogoproto.nullable) = false, + (gogoproto.stdtime) = true + ]; + + google.protobuf.Timestamp next_interest_claim_time = 5 [ + (gogoproto.nullable) = false, + (gogoproto.stdtime) = true + ]; +} + +// IndexBalances is the state of an Index, containing its meToken supply and all underlying asset balances. +message IndexBalances { + cosmos.base.v1beta1.Coin metoken_supply = 1 [(gogoproto.nullable) = false]; + repeated AssetBalance asset_balances = 2 [(gogoproto.nullable) = false]; +} + +// AssetBalance tracks how much of a single asset is held in leverage, reserves, fees and interest account. +message AssetBalance { + string denom = 1; + string leveraged = 2 [(gogoproto.customtype) = "cosmossdk.io/math.Int", (gogoproto.nullable) = false]; + string reserved = 3 [(gogoproto.customtype) = "cosmossdk.io/math.Int", (gogoproto.nullable) = false]; + string fees = 4 [(gogoproto.customtype) = "cosmossdk.io/math.Int", (gogoproto.nullable) = false]; + string interest = 5 [(gogoproto.customtype) = "cosmossdk.io/math.Int", (gogoproto.nullable) = false]; +} \ No newline at end of file diff --git a/proto/umee/metoken/v1/metoken.proto b/proto/umee/metoken/v1/metoken.proto new file mode 100644 index 0000000000..44618d5e73 --- /dev/null +++ b/proto/umee/metoken/v1/metoken.proto @@ -0,0 +1,105 @@ +syntax = "proto3"; +package umeenetwork.umee.metoken.v1; + +import "gogoproto/gogo.proto"; + +option go_package = "github.com/umee-network/umee/v5/x/metoken"; + +// Params defines the parameters for the metoken module. +message Params { + option (gogoproto.equal) = true; + + // Reserves Re-balancing Frequency in seconds, determines how often the re-balancing of the module reserves will be + // triggered + int64 rebalancing_frequency = 1; + + // Interest claiming frequency in seconds, determines how often metoken module will claim accrued interest from + // leverage module + int64 claiming_frequency = 2; +} + +// Index defines an index of assets that are allowed to swap and redeem for the Index's meToken, +// along with its metadata and parameters. +message Index { + option (gogoproto.equal) = true; + + // Denom is the denomination of the Index's meToken denom that will be given to user in exchange of accepted + // assets. + string denom = 1; + + // MaxSupply is the maximum amount of Index's meTokens can be minted. + // A swap that requires to mint more Index's meToken than this value will result in an error. + // Must be a non negative value. 0 means that there is no limit. + string max_supply = 2 [(gogoproto.customtype) = "cosmossdk.io/math.Int", (gogoproto.nullable) = false]; + + // Exponent is the power of ten by which to multiply, in order to convert + // an amount of the meToken for the exchange operations. + // Valid value: must be the same as the oracle.Denom.exponent. + uint32 exponent = 3; + + // Fee contains fee parameters used for swap and redemption fee calculations for all underlying + // assets in this index. + Fee fee = 4 [(gogoproto.nullable) = false]; + + // Accepted Assets is the list of underlying Tokens that can be swapped and redeemed for the Index's meToken, + // along with their token-specific parameters. + repeated AcceptedAsset accepted_assets = 5 [(gogoproto.nullable) = false]; +} + +// Fee are the parameters used for the calculation of the fee to be applied for swaps and redemptions and charged to +// the user. The usage of these parameters is explained here: +// https://github.com/umee-network/umee/tree/main/x/metoken#dynamic-fee +message Fee { + option (gogoproto.equal) = true; + + // Min fee is the minimum fee to be charged to the user. The applied fee will tend to decrease down to this value, + // when the accepted asset is undersupplied in the index. It must be less than Balanced and Max fees. + // Valid values: 0-1. + string min_fee = 1 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; + + // Balanced fee is the fee to be charged to the user when the index is balanced. It must be greater than min_fee and + // lower than max_fee + // Valid values: 0-1. + string balanced_fee = 2 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; + + // Max fee is the maximum fee to be charged to the user. The applied fee will tend to increase up to this value, + // when the accepted asset is oversupplied in the index. It must be greater than Min and Balanced fee. + // Valid values: 0-1. + string max_fee = 3 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; +} + +// AcceptedAsset is an asset that is accepted to participate in the Index's swaps and redemptions, along with its +// metadata and parameters +message AcceptedAsset { + option (gogoproto.equal) = true; + + // Denom is the denomination of the underlying asset. Must be the base + // denom as registered in the Bank module (so IBC denom for IBC tokens). + string denom = 1; + + // Reserve portion is the portion of swapped assets that will be kept in the metoken module as reserves, + // instead of supplied to the leverage module. It is also the + // portion that will be taken from metoken module reserves when a redemption occurs. + // Valid values: 0-1. + string reserve_portion = 2 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; + + // Target allocation is the portion of an accepted asset the Index is targeting to have. The sum of + // target allocations of every accepted asset in the Index should be equal to 1. + // Valid values: 0-1. + string target_allocation = 3 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; +} \ No newline at end of file diff --git a/proto/umee/metoken/v1/query.proto b/proto/umee/metoken/v1/query.proto new file mode 100644 index 0000000000..235f1e3f92 --- /dev/null +++ b/proto/umee/metoken/v1/query.proto @@ -0,0 +1,98 @@ +syntax = "proto3"; +package umeenetwork.umee.metoken.v1; + +import "google/api/annotations.proto"; +import "gogoproto/gogo.proto"; +import "cosmos/base/v1beta1/coin.proto"; +import "umee/metoken/v1/metoken.proto"; +import "umee/metoken/v1/genesis.proto"; + +option go_package = "github.com/umee-network/umee/v5/x/metoken"; + +option (gogoproto.goproto_getters_all) = false; + +// Query defines the gRPC querier service. +service Query { + // Params queries the parameters of the x/metoken module. + rpc Params(QueryParams) returns (QueryParamsResponse) { + option (google.api.http).get = "/umee/metoken/v1/params"; + } + + // Indexes queries for a specific or all the registered indexes. + rpc Indexes(QueryIndexes) + returns (QueryIndexesResponse) { + option (google.api.http).get = "/umee/metoken/v1/indexes"; + } + + // SwapFee computes fee that would be applied when executing MsgSwap. + rpc SwapFee(QuerySwapFee) + returns (QuerySwapFeeResponse) { + option (google.api.http).get = "/umee/metoken/v1/swap_fee"; + } + + // RedeemFee computes a fee that would be applied when executing MsgRedeem. + rpc RedeemFee(QueryRedeemFee) + returns (QueryRedeemFeeResponse) { + option (google.api.http).get = "/umee/metoken/v1/redeem_fee"; + } + + // IndexBalances queries for Index's balances of a specific or all the registered indexes. + rpc IndexBalances(QueryIndexBalances) + returns (QueryIndexBalancesResponse) { + option (google.api.http).get = "/umee/metoken/v1/index_balances"; + } +} + +// QueryParams defines the request structure for the Params gRPC service +// handler. +message QueryParams {} + +// QueryParamsResponse defines the response structure for the Params gRPC +// service handler. +message QueryParamsResponse { + Params params = 1 [(gogoproto.nullable) = false]; +} + +// QueryIndexes defines the request structure for the Indexes gRPC service handler. +// metoken_denom param is optional, if it is not informed the query will return all the Indexes. +message QueryIndexes { + string metoken_denom = 1; +} + +// QueryIndexesResponse defines the response structure for the Indexes gRPC service handler. +message QueryIndexesResponse { + repeated Index registry = 1 [(gogoproto.nullable) = false]; +} + +// QuerySwapFee defines the request structure for the SwapFee gRPC service handler. +message QuerySwapFee { + cosmos.base.v1beta1.Coin asset = 1 [(gogoproto.nullable) = false]; + string metoken_denom = 2; +} + +// QuerySwapFeeResponse defines the response structure for the SwapFee gRPC service handler. +message QuerySwapFeeResponse { + cosmos.base.v1beta1.Coin asset = 1 [(gogoproto.nullable) = false]; +} + +// QueryRedeemFee defines the request structure for the RedeemFee gRPC service handler. +message QueryRedeemFee { + cosmos.base.v1beta1.Coin metoken = 1 [(gogoproto.nullable) = false]; + string asset_denom = 2; +} + +// QueryRedeemFeeResponse defines the response structure for the RedeemFee gRPC service handler. +message QueryRedeemFeeResponse { + cosmos.base.v1beta1.Coin asset = 1 [(gogoproto.nullable) = false]; +} + +// QueryIndexBalances defines the request structure for the IndexBalances gRPC service handler. +// metoken_denom param is optional, if it is not informed the query will return all the Indexes. +message QueryIndexBalances { + string metoken_denom = 1; +} + +// QueryIndexBalanceResponse defines the response structure for the IndexBalances gRPC service handler. +message QueryIndexBalancesResponse { + repeated IndexBalances index_balances = 1 [(gogoproto.nullable) = false]; +} diff --git a/proto/umee/metoken/v1/tx.proto b/proto/umee/metoken/v1/tx.proto new file mode 100644 index 0000000000..21098919d8 --- /dev/null +++ b/proto/umee/metoken/v1/tx.proto @@ -0,0 +1,88 @@ +syntax = "proto3"; +package umeenetwork.umee.metoken.v1; + +import "cosmos/base/v1beta1/coin.proto"; +import "cosmos_proto/cosmos.proto"; +import "cosmos/msg/v1/msg.proto"; +import "gogoproto/gogo.proto"; +import "umee/metoken/v1/metoken.proto"; + +option go_package = "github.com/umee-network/umee/v5/x/metoken"; +option (gogoproto.goproto_getters_all) = false; + +// Msg defines the x/metoken module's Msg service. +service Msg { + // Swap defines a method for swapping an accepted asset for Index's meToken. + rpc Swap(MsgSwap) returns (MsgSwapResponse); + + // Redeem defines a method for redeeming Index's meToken for an accepted asset. + rpc Redeem(MsgRedeem) returns (MsgRedeemResponse); + + // GovSetParams is used by governance proposals to update parameters. + rpc GovSetParams(MsgGovSetParams) returns (MsgGovSetParamsResponse); + + // GovUpdateRegistry adds new index to the index registry or + // updates existing index with new settings. + rpc GovUpdateRegistry(MsgGovUpdateRegistry) returns (MsgGovUpdateRegistryResponse); +} + +// MsgSwap represents a user's request to swap assets for Index's meToken. +message MsgSwap { + // User is the account address swapping assets and the signer of the message. + string user = 1; + cosmos.base.v1beta1.Coin asset = 2 [(gogoproto.nullable) = false]; + string metoken_denom = 3; +} + +// MsgSwapResponse defines the Msg/Swap response type. +message MsgSwapResponse { + // Fee is the amount of accepted asset charged to the user as the fee for the transaction. + cosmos.base.v1beta1.Coin fee = 1 [(gogoproto.nullable) = false]; + // Returned is the amount of Index's meToken minted and returned to the user. + cosmos.base.v1beta1.Coin returned = 2 [(gogoproto.nullable) = false]; +} + +// MsgRedeem represents a user's request to redeem Index's meTokens for one of the accepted assets. +message MsgRedeem { + // User is the account address redeeming assets and the signer of the message. + string user = 1; + cosmos.base.v1beta1.Coin metoken = 2 [(gogoproto.nullable) = false]; + string asset_denom = 3; +} + +// MsgRedeemResponse defines the Msg/Redeem response type. +message MsgRedeemResponse { + // Returned is the amount of accepted asset returned to the user. + cosmos.base.v1beta1.Coin returned = 1 [(gogoproto.nullable) = false]; + // Fee is the amount of accepted asset charged to the user as the fee for the transaction. + cosmos.base.v1beta1.Coin fee = 2 [(gogoproto.nullable) = false]; +} + +// MsgGovSetParams defines the Msg/GovSetParams request type. +message MsgGovSetParams { + option (gogoproto.equal) = true; + option (cosmos.msg.v1.signer) = "authority"; + + // authority must be the address of the governance account. + string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + Params params = 2 [(gogoproto.nullable) = false]; +} + +// MsgGovSetParamsResponse defines the Msg/GovSetParams response type. +message MsgGovSetParamsResponse {} + +// MsgGovUpdateRegistry defines the Msg/GovUpdateRegistry request type. +message MsgGovUpdateRegistry { + option (gogoproto.equal) = true; + option (cosmos.msg.v1.signer) = "authority"; + + // authority is the address of the governance account. + string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + // add_index defines new index settings. + repeated Index add_index = 2 [(gogoproto.nullable) = false]; + // update_index defines the new settings for existing index. + repeated Index update_index = 3 [(gogoproto.nullable) = false]; +} + +// MsgGovUpdateRegistryResponse defines the Msg/GovUpdateRegistry response type. +message MsgGovUpdateRegistryResponse {} diff --git a/util/coin/coin.go b/util/coin/coin.go index 7adc96a914..19b8bf64fb 100644 --- a/util/coin/coin.go +++ b/util/coin/coin.go @@ -1,9 +1,50 @@ package coin import ( + sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" ) +var Exponents = map[int]sdk.Dec{ + -18: sdk.MustNewDecFromStr("0.000000000000000001"), + -17: sdk.MustNewDecFromStr("0.00000000000000001"), + -16: sdk.MustNewDecFromStr("0.0000000000000001"), + -15: sdk.MustNewDecFromStr("0.000000000000001"), + -14: sdk.MustNewDecFromStr("0.00000000000001"), + -13: sdk.MustNewDecFromStr("0.0000000000001"), + -12: sdk.MustNewDecFromStr("0.000000000001"), + -11: sdk.MustNewDecFromStr("0.00000000001"), + -10: sdk.MustNewDecFromStr("0.0000000001"), + -9: sdk.MustNewDecFromStr("0.000000001"), + -8: sdk.MustNewDecFromStr("0.00000001"), + -7: sdk.MustNewDecFromStr("0.0000001"), + -6: sdk.MustNewDecFromStr("0.000001"), + -5: sdk.MustNewDecFromStr("0.00001"), + -4: sdk.MustNewDecFromStr("0.0001"), + -3: sdk.MustNewDecFromStr("0.001"), + -2: sdk.MustNewDecFromStr("0.01"), + -1: sdk.MustNewDecFromStr("0.1"), + 0: sdk.MustNewDecFromStr("1.0"), + 1: sdk.MustNewDecFromStr("10.0"), + 2: sdk.MustNewDecFromStr("100.0"), + 3: sdk.MustNewDecFromStr("1000.0"), + 4: sdk.MustNewDecFromStr("10000.0"), + 5: sdk.MustNewDecFromStr("100000.0"), + 6: sdk.MustNewDecFromStr("1000000.0"), + 7: sdk.MustNewDecFromStr("10000000.0"), + 8: sdk.MustNewDecFromStr("100000000.0"), + 9: sdk.MustNewDecFromStr("1000000000.0"), + 10: sdk.MustNewDecFromStr("10000000000.0"), + 11: sdk.MustNewDecFromStr("100000000000.0"), + 12: sdk.MustNewDecFromStr("1000000000000.0"), + 13: sdk.MustNewDecFromStr("10000000000000.0"), + 14: sdk.MustNewDecFromStr("100000000000000.0"), + 15: sdk.MustNewDecFromStr("1000000000000000.0"), + 16: sdk.MustNewDecFromStr("10000000000000000.0"), + 17: sdk.MustNewDecFromStr("100000000000000000.0"), + 18: sdk.MustNewDecFromStr("1000000000000000000.0"), +} + // Zero returns new coin with zero amount func Zero(denom string) sdk.Coin { return sdk.NewInt64Coin(denom, 0) @@ -26,3 +67,11 @@ func Normalize(cs sdk.Coins) sdk.Coins { func New(denom string, amount int64) sdk.Coin { return sdk.NewInt64Coin(denom, amount) } + +// Negative1 creates a Coin with amount = -1 +func Negative1(denom string) sdk.Coin { + return sdk.Coin{ + Denom: denom, + Amount: sdkmath.NewInt(-1), + } +} diff --git a/x/leverage/client/tests/tests.go b/x/leverage/client/tests/tests.go index 8d7f2201d0..36e2a52447 100644 --- a/x/leverage/client/tests/tests.go +++ b/x/leverage/client/tests/tests.go @@ -2,7 +2,6 @@ package tests import ( sdk "github.com/cosmos/cosmos-sdk/types" - appparams "github.com/umee-network/umee/v5/app/params" itestsuite "github.com/umee-network/umee/v5/tests/cli" "github.com/umee-network/umee/v5/x/leverage/client/cli" diff --git a/x/leverage/keeper/collateral.go b/x/leverage/keeper/collateral.go index 200fc78494..31786d4d99 100644 --- a/x/leverage/keeper/collateral.go +++ b/x/leverage/keeper/collateral.go @@ -225,11 +225,11 @@ func (k *Keeper) checkCollateralShare(ctx sdk.Context, denom string) error { return nil } -// moduleMaxWithdraw calculates the maximum available amount of uToken to withdraw from the module given the amount of +// ModuleMaxWithdraw calculates the maximum available amount of uToken to withdraw from the module given the amount of // user's spendable tokens. The calculation first finds the maximum amount of non-collateral uTokens the user can // withdraw up to the amount in their wallet, then determines how much collateral can be withdrawn in addition to that. // The returned value is the sum of the two values. -func (k Keeper) moduleMaxWithdraw(ctx sdk.Context, spendableUTokens sdk.Coin) (sdkmath.Int, error) { +func (k Keeper) ModuleMaxWithdraw(ctx sdk.Context, spendableUTokens sdk.Coin) (sdkmath.Int, error) { denom := types.ToTokenDenom(spendableUTokens.Denom) // Get the module_available_liquidity diff --git a/x/leverage/keeper/internal_test.go b/x/leverage/keeper/internal_test.go index fbf024d920..932d11e207 100644 --- a/x/leverage/keeper/internal_test.go +++ b/x/leverage/keeper/internal_test.go @@ -4,7 +4,9 @@ import ( "github.com/cosmos/cosmos-sdk/codec" storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + "github.com/umee-network/umee/v5/x/metoken" "github.com/umee-network/umee/v5/x/leverage/types" ) @@ -33,6 +35,7 @@ func NewTestKeeper( bk, ok, enableLiquidatorQuery, + authtypes.NewModuleAddress(metoken.ModuleName), ) return k, TestKeeper{&k} } diff --git a/x/leverage/keeper/keeper.go b/x/leverage/keeper/keeper.go index 19de4d66fe..6b064042f2 100644 --- a/x/leverage/keeper/keeper.go +++ b/x/leverage/keeper/keeper.go @@ -12,6 +12,7 @@ import ( "github.com/umee-network/umee/v5/util/coin" "github.com/umee-network/umee/v5/x/leverage/types" + "github.com/umee-network/umee/v5/x/metoken" ) type Keeper struct { @@ -21,6 +22,7 @@ type Keeper struct { bankKeeper types.BankKeeper oracleKeeper types.OracleKeeper liquidatorQueryEnabled bool + meTokenAddr sdk.AccAddress tokenHooks []types.TokenHooks bondHooks []types.BondHooks @@ -33,6 +35,7 @@ func NewKeeper( bk types.BankKeeper, ok types.OracleKeeper, enableLiquidatorQuery bool, + meTokenAddr sdk.AccAddress, ) Keeper { // set KeyTable if it has not already been set if !paramSpace.HasKeyTable() { @@ -46,6 +49,7 @@ func NewKeeper( bankKeeper: bk, oracleKeeper: ok, liquidatorQueryEnabled: enableLiquidatorQuery, + meTokenAddr: meTokenAddr, } } @@ -108,7 +112,14 @@ func (k Keeper) Supply(ctx sdk.Context, supplierAddr sdk.AccAddress, coin sdk.Co } // The uTokens are sent to supplier address - if err = k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, supplierAddr, uTokens); err != nil { + // Only base accounts and x/metoken module account are supported. + if supplierAddr.Equals(k.meTokenAddr) { + err = k.bankKeeper.SendCoinsFromModuleToModule(ctx, types.ModuleName, metoken.ModuleName, uTokens) + } else { + err = k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, supplierAddr, uTokens) + } + + if err != nil { return sdk.Coin{}, err } @@ -156,14 +167,16 @@ func (k Keeper) Withdraw(ctx sdk.Context, supplierAddr sdk.AccAddress, uToken sd if collateralAmount.LT(amountFromCollateral) { return sdk.Coin{}, isFromCollateral, types.ErrInsufficientBalance.Wrapf( "%s uToken balance + %s from collateral is less than %s to withdraw", - amountFromWallet, collateralAmount, uToken) + amountFromWallet, collateralAmount, uToken, + ) } unbondedCollateral := k.unbondedCollateral(ctx, supplierAddr, uToken.Denom) if unbondedCollateral.Amount.LT(amountFromCollateral) { return sdk.Coin{}, isFromCollateral, types.ErrBondedCollateral.Wrapf( "%s unbonded collateral is less than %s to withdraw from collateral", - unbondedCollateral, amountFromCollateral) + unbondedCollateral, amountFromCollateral, + ) } // reduce the supplier's collateral by amountFromCollateral @@ -180,8 +193,15 @@ func (k Keeper) Withdraw(ctx sdk.Context, supplierAddr sdk.AccAddress, uToken sd } // send the base assets to supplier + // Only base accounts and x/metoken module account are supported. tokens := sdk.NewCoins(token) - if err = k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, supplierAddr, tokens); err != nil { + if supplierAddr.Equals(k.meTokenAddr) { + err = k.bankKeeper.SendCoinsFromModuleToModule(ctx, types.ModuleName, metoken.ModuleName, tokens) + } else { + err = k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, supplierAddr, tokens) + } + + if err != nil { return sdk.Coin{}, isFromCollateral, err } @@ -216,7 +236,8 @@ func (k Keeper) Borrow(ctx sdk.Context, borrowerAddr sdk.AccAddress, borrow sdk. borrowed := k.GetBorrowerBorrows(ctx, borrowerAddr) if err := k.bankKeeper.SendCoinsFromModuleToAccount( - ctx, types.ModuleName, borrowerAddr, sdk.NewCoins(borrow)); err != nil { + ctx, types.ModuleName, borrowerAddr, sdk.NewCoins(borrow), + ); err != nil { return err } @@ -287,7 +308,8 @@ func (k Keeper) Decollateralize(ctx sdk.Context, borrowerAddr sdk.AccAddress, uT if unbondedCollateral.Amount.LT(uToken.Amount) { return types.ErrBondedCollateral.Wrapf( "%s unbonded collateral uTokens are less than %s to decollateralize", - unbondedCollateral, uToken) + unbondedCollateral, uToken, + ) } // Decollateralizing uTokens withdraws them from the module account and returns them to the user diff --git a/x/leverage/keeper/msg_server.go b/x/leverage/keeper/msg_server.go index 01d2973662..c4d982e732 100644 --- a/x/leverage/keeper/msg_server.go +++ b/x/leverage/keeper/msg_server.go @@ -126,7 +126,7 @@ func (s msgServer) MaxWithdraw( } // Get the total available for uToken to prevent withdraws above this limit. - uTokenTotalAvailable, err := s.keeper.moduleMaxWithdraw(ctx, userSpendableUtokens) + uTokenTotalAvailable, err := s.keeper.ModuleMaxWithdraw(ctx, userSpendableUtokens) if err != nil { return nil, err } diff --git a/x/metoken/README.md b/x/metoken/README.md new file mode 100644 index 0000000000..14d4735b83 --- /dev/null +++ b/x/metoken/README.md @@ -0,0 +1,480 @@ +# meToken Module + +## Abstract + +This document specifies the `x/metoken` module of the Umee chain. + +meToken is a new Token that represents an Index composed of assets used for swaps and redemptions. It can be minted +during the swap of the Index accepted assets and burned to redeem any Index accepted asset. Each Index will have a +unique name for the meToken that represents it. Its price is determined by the average price of the assets in the Index. + +The `metoken` module allows users to swap and redeem accepted assets for an Index meToken. The Index meToken will +maintain the parity between underlying assets given a specific configuration. The module transfers part of the +supplied assets to the `leverage` module in order to accrue interest. + +The `metoken` module depends directly on `x/leverage` for supplying and withdrawing assets, `x/oracle` for assets +prices and the cosmos `x/bank` module for balance updates (coins). + +## Contents + +1. **[Concepts](#concepts)** + - [Accepted Assets](#accepted-assets) + - [Index Parameters](#index-parameters) + - [Dynamic meToken Price](#dynamic-metoken-price) + - [Initial Price](#initial-price) + - [Swapping and Redeeming](#swapping-and-redeeming) + - Important Derived Values: + - [Dynamic Fee](#dynamic-fee) + - [Reserves](#reserves) + - [Reserves Re-balancing](#reserves-re-balancing) + - [Interest](#interest) + - [Claiming Interests](#claiming-interests) +2. **[State](#state)** +3. **[Queries](#queries)** +4. **[Messages](#messages)** +5. **[Update Registry Proposal](#update-registry-proposal)** +6. **[Events](#events)** +7. **[Parameters](#params)** +8. **[EndBlock](#end-block)** + +## Concepts + +### Accepted Assets + +At the foundation of the `metoken` module is the _Index Registry_, which contains a list of Indexes with their meTokens, accepted assets and other parameters. + +This list is controlled by the chain governance. Assets that are not in the index registry are not available for swapping or redeeming for the Index meToken. + +Once an asset is added to an Index, it cannot be removed. However, its `target_allocation` can be changed to incentivize or disincentivize its presence in the Index. + +### Index Parameters + +The Index will have the following parameters: + +- meToken denom: a denom of the meToken Index that will be given to user in exchange for accepted assets. +- meToken max supply: the maximum amount of meTokens (in specific Index) that can be minted. A swap that requires to + mint more meToken than this value will result in an error. +- Fees: every fee is calculated and charged to the user in the asset that is used in the operation. The calculation + will be explained below, the following values will be used as parameters for that calculation: + - Min fee: the minimum fee to be charged to the user. The applied fee will tend to decrease down to this value, + when the accepted asset is undersupplied in the index. It must be less than Balanced and Max fees. + Valid values: `[0-1]`. + - Balanced fee: the fee to be charged to the user when the index is balanced. It must be greater than Min fee and + lower than Max fee, it cannot be 0. + Valid values: `[0-1]`. + - Max fee: the maximum fee to be charged to the user. The applied fee will tend to increase up to this value, + when the accepted asset is oversupplied in the index. It must be greater than Min and Balanced fees. + Valid values: `[0-1]`. +- Accepted Assets: a list where each asset will have the following parameters: + - Asset denom. + - Reserve portion: the portion of swapped assets that will be transferred to `metoken` module as reserves, and the + minimum portion that will be taken from `metoken` module reserves when a redemption occurs. Valid values: `[0-1]`. + - Target allocation: the portion of an accepted asset the Index is targeting to have. The sum of + `target_allocation` of every accepted asset in the Index should be equal to 1. Valid values: `[0-1]`. + +### Dynamic meToken Price + +Every meToken will have a dynamic price. It will be based on the underlying assets total value, divided by the +amount of minted meTokens, and calculated for every operation. The formula for the price is as follows: + +``` yaml +metoken_price = + (asset1_amount * asset1_price + asset2_amount * asset2_price + assetN_amount * assetN_price) / metoken_minted + +As an example, using the following Index: + - 2.5 WETH at price: 1858.5 USD + - 6140 USDT at price: 0.99415 USD + - 1.75013446 WBTC at price: 28140.50585 USD + - 6 minted meTokens + +The price of meToken would be: +metoken_price = (2.5 * 1858.5 + 6140 * 0.99415 + 1.75013446 * 28140.50585) / 6 +metoken_price = 10000 USD +``` + +#### Initial price + +The initial price for the first transaction will be determined by the average price of the underlying assets, +divided by the quantity of accepted assets in the Index, using the following formula: + +``` yaml +metoken_price = (asset1_price + asset2_price + assetN_price) / N + +As an example for an Index composed of: + - USDC at price: 1.018 USD + - USDT at price: 0.983 USD + - IST at price: 1.035 USD + +The price of meToken for the initial swap would be: +metoken_price = (1.018 + 0.983 + 1.035) / 3 +metoken_price = 1.012 USD +``` + +### Swapping and Redeeming + +Users have the following actions available to them: + +- Swap accepted asset for Index meToken. Every accepted asset can be swapped for the Index meToken. The exchange + rate will be determined using prices from `x/oracle` module for the accepted assets and the Index meToken + dynamic price. The user will need to pay a [Dynamic Fee](#dynamic-fee) for the swap. The fee will be charged in + the accepted asset the Index meToken is offered for. + + Index meToken amount needed for the swap will be minted and transferred to the user's account, while the accepted + asset for the swap will be transferred to the `leverage` module pools and the `metoken` module reserves. + The portion to be transferred to each one is determined by the _Index Registry_ configuration of each accepted asset. + + In case the defined portion to transfer to the `x/leverage` is not possible, because of the `leverage` module max + supply cap for a particular token, the remaining part will be transferred to `x/metoken` reserves. + +- Redeem Index meToken for accepted asset. Index meToken can be redeemed for every accepted asset. The exchange + rate will be determined using prices from `x/oracle` module for the accepted assets and the Index meToken dynamic + price. The user will need to pay a [Dynamic Fee](#dynamic-fee) for the redemption. The fee will be charged in the + accepted asset the Index meToken is redeemed for. + + Index meToken amount needed for the redemption will be withdrawn from the user's account and burned, while + the chosen asset to redeem will be transferred from the `leverage` module pools and the `metoken` module reserves + to the user's account. The portion to be withdrawn from each one is determined by the _Index Registry_ + configuration of each accepted asset. + + When it is not possible to withdraw the needed portion from the `leverage` module given its own constraints, the part + taken from the reserves will increase in order to complete the redemption, if possible. + +### Derived Values + +Some important quantities that govern the behavior of the `metoken` module are derived from a combination of +parameters. The math and reasoning behind these values are presented below. + +As a reminder, the following values are always available as a basis for calculations: + +- Account Token balances, available through the `bank` module. +- Index parameters from the _Index Registry_. +- Total reserves of any tokens, saved in `metoken` module reserve balance. +- Total amount of any tokens transferred to the `leverage` module, stored in `metoken` module [State](#state). +- The price of every underlying asset taken from `oracle` module. + +The more complex derived values must use the values above as basis. + +#### Dynamic Fee + +The fee to be applied for the swap or the redemption will be dynamic and based on the deviation from the +`target_allocation` of an asset and its current allocation in the Index. Every charged fee to the user will be +transferred to the `metoken` module balance and the value will be added to the [State](#state). In that way it is +possible to discriminate between the reserves, fees and interest saved on the `metoken` module balance. +The formula for calculating the dynamic fee is as follows: + +``` text +dynamic_fee = balanced_fee + [allocation_delta * (balanced_fee / 100)] + +If the dynamic_fee is lower than min_fee -> dynamic_fee = min_fee +If the dynamic_fee is greater than max_fee -> dynamic_fee = max_fee + +where: +allocation_delta for the swap = (current_allocation - target_allocation) / target_allocation +allocation_delta for the redemption = (target_allocation - current_allocation) / target_allocation +``` + +Example for the meUSD index, and the following fee and accepted assets: + +``` yaml +- Fee: + - Min: 0.001 + - Balanced: 0.2 + - Max: 0.5 + +- USDT: + - reserve_portion: 0.2 + - target_allocation: 0.33333 +- USDC: + - reserve_portion: 0.2 + - target_allocation: 0.33333 +- IST: + - reserve_portion: 0.2 + - target_allocation: 0.33333 + +After several swaps the index has 1200 USDT, 760 USDC and 3000 IST. Total supply: 4960. + +Prices: + - USDT = 0.998 USD + - USDC = 1.0 USD + - IST = 1.02 USD + - meUSD_price = (1200 * 0.998 + 760 * 1.0 + 3000 * 1.02) / 4960 = 1.011612903 + +Calculations for swap: +- USDT allocation_delta: (0.24193 - 0.33333)/0.33333 = -0.2742027 +- USDC allocation_delta: (0.15322 - 0.33333)/0.33333 = -0.5403354 +- IST allocation_delta: (0.60483 - 0.33333)/0.33333 = 0.8145081 + +- USDT fee: 0.2 - 0.2742027*0.2 = 0.14515 +- USDC fee: 0.2 - 0.5403354*0.2 = 0.09193 +- IST fee: 0.2 + 0.8145081*0.2 = 0.36290 + +Following this values, let's simulate a swap. A user wants to buy meUSD for 10 USDT. + +meUSD = 10 * (0.998 / 1.011612903) * (1 - 0.14515) +meUSD = 8.433465976 + +The user will receive 8.433465976 meUSD. 1.14515 USDT is the fee and 8.5485 USDT will be split +between the reserves and the liquidity for the leverage module based on the reserve_portion. +6.8388 USDT will be transferred to the leverage module and 1.7097 USDT will be transferred to reserves. + +Calculations for redemption: +- USDT allocation_delta: (0.33333 - 0.24193)/0.33333 = 0.2742027 +- USDC allocation_delta: (0.33333 - 0.15322)/0.33333 = 0.5403354 +- IST allocation_delta: (0.33333 - 0.60483)/0.33333 = -0.8145081 + +- USDT fee: 0.2 + 0.2742027*0.2 = 0.25484 +- USDC fee: 0.2 + 0.5403354*0.2 = 0.30806 +- IST fee: 0.2 - 0.8145081*0.2 = 0.03709 + +Following this values, let's simulate a redemption. A user wants to sell 20 meUSD for IST. + +IST = 20 * (1.011612903 / 1.02) * (1 - 0.03709) +IST = 19.09984668 + +The user will receive 19.09984668 IST. 0.7357004428 IST will be the total saved fee. 20 meUSD will be taken from the +user's account and burned. +The total value to be withdrawn is 19.83554712 IST and it will be split between the reserves and the liquidity from the +leverage module based on the reserve_portion. +15.8684377 IST will be taken from leverage module and 3.967109424 IST from the reserves. +``` + +Another example with an edge case where the min and max fee are used: + +``` yaml +- Fee: + - Min: 0.01 + - Balanced: 0.3 + - Max: 0.8 + +- USDT: + - reserve_portion: 0.3 + - target_allocation: 0.25 +- USDC: + - reserve_portion: 0.3 + - target_allocation: 0.25 +- IST: + - reserve_portion: 0.3 + - target_allocation: 0.25 +- MSK: + - reserve_portion: 0.3 + - target_allocation: 0.25 + +After several swaps the index has 3500 USDT, 100 USDC, 300 IST and 0 MSK. Total supply: 3900. + +Prices: + - USDT = 0.998 USD + - USDC = 0.99993 USD + - IST = 1.02 USD + - MSK = 1.0 USD + - meUSD_price = (3500 * 0.998 + 100 * 0.99993 + 300 * 1.02 + 0 * 1.0) / 3900 = 0.9997417949 + +Calculations for swap: +- USDT allocation_delta: (0.89743 - 0.25)/0.25 = 2.58972 +- USDC allocation_delta: (0.02564 - 0.25)/0.25 = -0.89744 +- IST allocation_delta: (0.07692 - 0.25)/0.25 = -0.69232 +- MSK allocation_delta: (0.0 - 0.25)/0.25 = -1.0 + +- USDT fee: 0.3 + 2.58972*0.3 = 1.07691 -> This exceedes the max fee (0.8). In this case the max fee will be used. +- USDC fee: 0.3 - 0.89744*0.3 = 0.03076 +- IST fee: 0.3 - 0.69232*0.3 = 0.09230 +- MSK fee: 0.3 - 1.0*0.3 = 0 -> This is below the min fee (0.01). For this swap the min fee will be applied. + +Following this values, let's simulate a swap. A user wants to buy meUSD for 10 MSK. + +meUSD = 10 * (1.0 / 0.9997417949) * (1 - 0.01) +meUSD = 9.902556891 + +The user will receive 9.902556891 meUSD. 0.1 MSK will be the total saved fee and 9.9 MSK will be splitted +between the reserves and the liquidity for the leverage module based on the reserve_portion. +6.93 MSK will be transferred to the leverage module and 2.97 MSK will be transferred to reserves. + +Calculations for redemption: +- USDT allocation_delta: (0.25 - 0.89743)/0.25 = -2.58972 +- USDC allocation_delta: (0.25 - 0.02564)/0.25 = 0.8974358 +- IST allocation_delta: (0.25 - 0.07692)/0.25 = 0.69232 +- MSK allocation_delta: (0.25 - 0.0)/0.25 = 1.0 + +- USDT fee: 0.3 - 2.58972*0.3 = -0.47691 -> This is below the min fee (0.01) and also the fee can't be negative. For this swap the min fee will be applied. +- USDC fee: 0.3 + 0.89744*0.3 = 0.56923 +- IST fee: 0.3 + 0.69232(0.3 = 0.50769 +- MSK fee: 0.3 + 1.0*0.3 = 0.6 -> In this case the redeption is not possible since there is no MSK liquidity anyway. + +Following this values, let's simulate a redemption. A user wants to sell 20 meUSD for USDC. + +USDC = 20 * (0.9997417949 / 0.99993) * (1 - 0.56923) +USDC = 8.613778424 + +The user will receive 8.613778424 USDC. 11.38245721 USDC will be the total saved fee. 20 meUSD will be taken from the +user's account and burned. +The total value to be withdrawn is 19.99623563 USDC and it will be splitted between the reserves and the liquidity from the +leverage module based on the reserve_portion. +13.99736494 USDC will be taken from leverage module and 5.99887069 USDC from the reserves. +``` + +### Reserves + +The `metoken` module will have its own reserves to stabilize the processing of the withdrawals. A portion of +every swap will be transferred to the reserves and a percentage of every withdrawal will be taken from the reserves. +This portion is determined by the parameters of every asset in the Index. + +All the reserves will be saved to the `metoken` module balance along with all the fees and the claimed interest. The +amount of fees for every asset will be saved to the `metoken` module [State](#state) as well as the amount of the +interests claimed from the `leverage` module. The reserves are equal to `balance - fee - interest` for every asset. + +#### Reserves Re-balancing + +The frequency of the Reserves Re-balancing will be determined by module parameter `rebalancing_frequency`. +The workflow for every asset of each Index is as follows: + + 1. Get the amount of Token transferred to the `leverage` module, stored in `metoken` module [State](#state). + 2. Get the amount of Token maintained in the `metoken` module balance and deduct it by the fee amount and the + interests amount, both stored in `metoken` module [State](#state). The result is the amount of Token reserves. + 3. Check if the portion of reserves is below the desired and transfer the missing amount from `leverage` module to + `metoken` reserves, or vice versa if required. + 4. Update `next_rebalancing_time`, stored in the `metoken` module [State](#state) adding the `rebalancing_frequency` to + the current block time. + +### Interest + +Every supply of liquidity to `leverage` module will produce interests. The interest will be accruing based on the +settings of the supplied Token in the [Token Registry](https://github.com/umee-network/umee/tree/main/x/leverage#accepted-assets) +and the [Supplying APY](https://github.com/umee-network/umee/tree/main/x/leverage#supplying-apy). Its usage will be +decided in future iterations. + +#### Claiming Interests + +Every `claim_interests_frequency` a process that withdraws all the accrued interest of every asset supplied to the +`leverage` module will be triggered. This process consists of the following steps: + + 1. Get the amount of Token existing in the `leverage` module, stored in the `leverage` module balance for `metoken` + module address and Token denom. + 2. Get the amount of Token transferred to the `leverage` module, stored in `metoken` module [State](#state). + 3. Calculate the delta 1) - 2), this will be the accrued interest. + 4. Withdraw accrued interest from `leverage` module. + 5. Update the claimed interest in the `metoken` module [State](#state). + 6. Update `next_interest_claiming_time`, stored in the `metoken` module [State](#state) adding the + `claim_interests_frequency` to the current block time. + +## State + +The `x/metoken` module keeps the following objects in state: + +- Index Registry: `0x01 | index_name -> Index` +- Module Balances of every Index: `0x02 | metoken_denom -> Balance`, where `Balance` is: + - `metoken_supply`: total meToken Supply. + - `leveraged`: transferred to `leverage` module Amount. + - `reserved`: total `metoken` module reserves. + - `fees`: total `fees` saved in reserves. + - `interests`: total `interest` claimed from `x/leverage`. +- Next Time (unix timestamp) for Reserves Re-balancing: `0x03 -> int64` +- Next Time (unix timestamp) for Claiming Interests: `0x04 -> int64` + +The following serialization methods are used unless otherwise stated: + +- `sdk.Dec.Marshal()` and `sdk.Int.Marshal()` for numeric types +- `cdc.Marshal` and `cdc.Unmarshal` for `gogoproto/types.Int64Value` wrapper around int64 + +## Queries + +See (LINK TO BE ADDED) for list of supported queries. + +## Messages + +See (LINK TO BE ADDED) for list of supported messages. + +## Update Registry Proposal + +`Update-Registry` gov proposal will add the new index to index registry or update the existing index with new settings. + +### CLI + +```bash +umeed tx gov submit-proposal [path-to-proposal-json] [flags] +``` + +Example: + +```bash +umeed tx gov submit-proposal /path/to/proposal.json --from umee1.. + +# Note `authority` will be gov module account address in proposal.json +umeed q auth module-accounts -o json | jq '.accounts[] | select(.name=="gov") | .base_account.address' +``` + +where `proposal.json` contains: + +```json +{ + "messages": [ + { + "@type": "/umeenetwork.umee.metoken.v1.MsgGovUpdateRegistry", + "authority": "umee10d07y265gmmuvt4z0w9aw880jnsr700jg5w6jp", + "title": "Update the meToken Index Registry", + "description": "Add me/USD Index, Update me/EUR Index", + "add_indexes": [ + { + "metoken_denom": "me/USD", + "metoken_max_supply": "2000000", + "fee": { + "min": "0.01", + "balanced": "0.2", + "max": "0.6" + }, + "accepted_assets": [ + { + "asset_denom": "USDT", + "reserve_portion": "0.2", + "total_allocation": "0.333" + }, + { + "asset_denom": "USDC", + "reserve_portion": "0.2", + "total_allocation": "0.334" + }, + { + "asset_denom": "IST", + "reserve_portion": "0.2", + "total_allocation": "0.333" + } + ] + } + ], + "update_indexes": [ + { + "metoken_denom": "me/EUR", + "metoken_max_supply": "2000000", + "fee": { + "min": "0.001", + "balanced": "0.3", + "max": "0.9" + }, + "accepted_assets": [ + { + "asset_denom": "EURC", + "reserve_portion": "0.3", + "total_allocation": "0.333" + } + ] + } + ] + } + ], + "metadata": "", + "deposit": "100uumee" +} +``` + +## Events + +See (LINK TO BE ADDED) for list of supported events. + +## Params + +See (LINK TO BE ADDED) for list of supported module params. + +## End Block + +Every block, the `metoken` module runs the following steps in order: + +- Re-balance Reserves if at or after `next_rebalancing_time`. +- Claim interests from the `leverage` module if at or after `next_interest_claiming_time`. diff --git a/x/metoken/client/cli/query.go b/x/metoken/client/cli/query.go new file mode 100644 index 0000000000..37c4751ee0 --- /dev/null +++ b/x/metoken/client/cli/query.go @@ -0,0 +1,180 @@ +package cli + +import ( + "fmt" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/umee-network/umee/v5/util/cli" + "github.com/umee-network/umee/v5/x/metoken" +) + +// GetQueryCmd returns the CLI query commands for the x/metoken module. +func GetQueryCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: metoken.ModuleName, + Short: fmt.Sprintf("Querying commands for the %s module", metoken.ModuleName), + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmd.AddCommand( + GetCmdQueryParams(), + GetCmdIndexes(), + GetCmdIndexBalances(), + GetCmdSwapFee(), + GetCmdRedeemFee(), + ) + + return cmd +} + +// GetCmdQueryParams creates a Cobra command to query for the x/metoken module parameters. +func GetCmdQueryParams() *cobra.Command { + cmd := &cobra.Command{ + Use: "params", + Args: cobra.NoArgs, + Short: "Query the metoken module parameters", + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + queryClient := metoken.NewQueryClient(clientCtx) + resp, err := queryClient.Params(cmd.Context(), &metoken.QueryParams{}) + return cli.PrintOrErr(resp, err, clientCtx) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + return cmd +} + +// GetCmdIndexes creates a Cobra command to query for the x/metoken module registered Indexes. +// metoken_denom is optional, if it isn't provided then all the indexes will be returned. +func GetCmdIndexes() *cobra.Command { + cmd := &cobra.Command{ + Use: "indexes [metoken_denom]", + Args: cobra.MaximumNArgs(1), + Short: "Get all the registered indexes in the x/metoken module or search for a specific index with" + + " metoken_denom.", + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + queryClient := metoken.NewQueryClient(clientCtx) + queryReq := metoken.QueryIndexes{} + if len(args) > 0 { + queryReq.MetokenDenom = args[0] + } + + resp, err := queryClient.Indexes(cmd.Context(), &queryReq) + return cli.PrintOrErr(resp, err, clientCtx) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + return cmd +} + +// GetCmdSwapFee creates a Cobra command to query for the SwapFee +// Both arguments are required: +// coin: the coin that is taken as base for the fee calculation. +func GetCmdSwapFee() *cobra.Command { + cmd := &cobra.Command{ + Use: "swap-fee [coin] [metoken_denom]", + Args: cobra.ExactArgs(2), + Short: "Get the fee amount to be charged for a swap. Both args are required.", + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + queryClient := metoken.NewQueryClient(clientCtx) + queryReq := metoken.QuerySwapFee{} + + asset, err := sdk.ParseCoinNormalized(args[0]) + if err != nil { + return err + } + queryReq.Asset = asset + queryReq.MetokenDenom = args[1] + + resp, err := queryClient.SwapFee(cmd.Context(), &queryReq) + return cli.PrintOrErr(resp, err, clientCtx) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + return cmd +} + +// GetCmdRedeemFee creates a Cobra command to query for the RedeemFee +// Both arguments are required: +// metoken: the meToken coin that is taken as base for the fee calculation. +func GetCmdRedeemFee() *cobra.Command { + cmd := &cobra.Command{ + Use: "redeem-fee [metoken] [asset_denom]", + Args: cobra.ExactArgs(2), + Short: "Get the fee amount to be charged for a redeem. Both args are required.", + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + queryClient := metoken.NewQueryClient(clientCtx) + queryReq := metoken.QueryRedeemFee{} + + metoken, err := sdk.ParseCoinNormalized(args[0]) + if err != nil { + return err + } + queryReq.Metoken = metoken + queryReq.AssetDenom = args[1] + + resp, err := queryClient.RedeemFee(cmd.Context(), &queryReq) + return cli.PrintOrErr(resp, err, clientCtx) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + return cmd +} + +// GetCmdIndexBalances creates a Cobra command to query for the x/metoken module Indexes assets balances +// metoken_denom is optional, if it isn't provided then all the balances will be returned. +func GetCmdIndexBalances() *cobra.Command { + cmd := &cobra.Command{ + Use: "index-balance [metoken_denom]", + Args: cobra.MaximumNArgs(1), + Short: "Get all the indexes' balances in the x/metoken module or search for a specific index with" + + " metoken_denom.", + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + queryClient := metoken.NewQueryClient(clientCtx) + queryReq := metoken.QueryIndexBalances{} + if len(args) > 0 { + queryReq.MetokenDenom = args[0] + } + resp, err := queryClient.IndexBalances(cmd.Context(), &queryReq) + return cli.PrintOrErr(resp, err, clientCtx) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + return cmd +} diff --git a/x/metoken/client/cli/tx.go b/x/metoken/client/cli/tx.go new file mode 100644 index 0000000000..b23e2509d1 --- /dev/null +++ b/x/metoken/client/cli/tx.go @@ -0,0 +1,85 @@ +package cli + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/tx" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/spf13/cobra" + "github.com/umee-network/umee/v5/x/metoken" +) + +// GetTxCmd returns the CLI transaction commands for the x/metoken module. +func GetTxCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: metoken.ModuleName, + Short: fmt.Sprintf("Transaction commands for the %s module", metoken.ModuleName), + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmd.AddCommand( + GetCmdSwap(), + GetCmdRedeem(), + ) + + return cmd +} + +// GetCmdSwap creates a Cobra command to generate or broadcast a transaction with a MsgSwap message. +// Both arguments are required. +func GetCmdSwap() *cobra.Command { + cmd := &cobra.Command{ + Use: "swap [coin] [metoken_denom]", + Args: cobra.ExactArgs(2), + Short: "swap a specified amount of an accepted asset for the selected meToken", + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + asset, err := sdk.ParseCoinNormalized(args[0]) + if err != nil { + return err + } + + msg := metoken.NewMsgSwap(clientCtx.GetFromAddress(), asset, args[1]) + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + return cmd +} + +// GetCmdRedeem creates a Cobra command to generate or broadcast a transaction with a MsgRedeem message. +// Both arguments are required. +func GetCmdRedeem() *cobra.Command { + cmd := &cobra.Command{ + Use: "redeem [metoken] [redeem_denom]", + Args: cobra.ExactArgs(2), + Short: "redeem a specified amount of meToken for the selected asset accepted by the index", + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + meToken, err := sdk.ParseCoinNormalized(args[0]) + if err != nil { + return err + } + + msg := metoken.NewMsgRedeem(clientCtx.GetFromAddress(), meToken, args[1]) + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + return cmd +} diff --git a/x/metoken/codec.go b/x/metoken/codec.go new file mode 100644 index 0000000000..ae7fec4a68 --- /dev/null +++ b/x/metoken/codec.go @@ -0,0 +1,46 @@ +package metoken + +import ( + "github.com/cosmos/cosmos-sdk/codec" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/msgservice" +) + +var ( + amino = codec.NewLegacyAmino() + + // ModuleCdc references the global x/metoken module codec. Note, the codec + // should ONLY be used in certain instances of tests and for JSON encoding as + // Amino is still used for that purpose. + ModuleCdc = codec.NewAminoCodec(amino) +) + +func init() { + RegisterLegacyAminoCodec(amino) + cryptocodec.RegisterCrypto(amino) + amino.Seal() +} + +// RegisterLegacyAminoCodec registers the necessary x/metoken interfaces and +// concrete types on the provided LegacyAmino codec. These types are used for +// Amino JSON serialization. +func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + cdc.RegisterConcrete(&MsgGovSetParams{}, "umee/metoken/MsgGovSetParams", nil) + cdc.RegisterConcrete(&MsgGovUpdateRegistry{}, "umee/metoken/MsgGovUpdateRegistry", nil) + cdc.RegisterConcrete(&MsgSwap{}, "umee/metoken/MsgSwap", nil) + cdc.RegisterConcrete(&MsgRedeem{}, "umee/metoken/MsgRedeem", nil) +} + +func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { + registry.RegisterImplementations( + (*sdk.Msg)(nil), + &MsgGovSetParams{}, + &MsgGovUpdateRegistry{}, + &MsgSwap{}, + &MsgRedeem{}, + ) + + msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) +} diff --git a/x/metoken/events.pb.go b/x/metoken/events.pb.go new file mode 100644 index 0000000000..b394920cc7 --- /dev/null +++ b/x/metoken/events.pb.go @@ -0,0 +1,1407 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: umee/metoken/v1/events.proto + +package metoken + +import ( + fmt "fmt" + _ "github.com/cosmos/cosmos-proto" + types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// EventSwap is emitted on Msg/Swap +type EventSwap struct { + // meToken recipient bech32 address. + Recipient string `protobuf:"bytes,1,opt,name=recipient,proto3" json:"recipient,omitempty"` + // Asset provided for the swap. + Asset types.Coin `protobuf:"bytes,2,opt,name=asset,proto3" json:"asset"` + // meToken received by the recipient in exchange for the provided asset. + Metoken types.Coin `protobuf:"bytes,3,opt,name=metoken,proto3" json:"metoken"` + // Fee provided for the swap. + Fee types.Coin `protobuf:"bytes,4,opt,name=fee,proto3" json:"fee"` +} + +func (m *EventSwap) Reset() { *m = EventSwap{} } +func (m *EventSwap) String() string { return proto.CompactTextString(m) } +func (*EventSwap) ProtoMessage() {} +func (*EventSwap) Descriptor() ([]byte, []int) { + return fileDescriptor_503099fd3bb02aa5, []int{0} +} +func (m *EventSwap) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *EventSwap) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_EventSwap.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 *EventSwap) XXX_Merge(src proto.Message) { + xxx_messageInfo_EventSwap.Merge(m, src) +} +func (m *EventSwap) XXX_Size() int { + return m.Size() +} +func (m *EventSwap) XXX_DiscardUnknown() { + xxx_messageInfo_EventSwap.DiscardUnknown(m) +} + +var xxx_messageInfo_EventSwap proto.InternalMessageInfo + +// EventRedeem is emitted on Msg/Redeem +type EventRedeem struct { + // Asset recipient bech32 address. + Recipient string `protobuf:"bytes,1,opt,name=recipient,proto3" json:"recipient,omitempty"` + // meToken provided for the redemption. + Metoken types.Coin `protobuf:"bytes,2,opt,name=metoken,proto3" json:"metoken"` + // Asset received by the recipient in exchange for the provided meToken. + Asset types.Coin `protobuf:"bytes,3,opt,name=asset,proto3" json:"asset"` + // Fee provided for the redemption. + Fee types.Coin `protobuf:"bytes,4,opt,name=fee,proto3" json:"fee"` +} + +func (m *EventRedeem) Reset() { *m = EventRedeem{} } +func (m *EventRedeem) String() string { return proto.CompactTextString(m) } +func (*EventRedeem) ProtoMessage() {} +func (*EventRedeem) Descriptor() ([]byte, []int) { + return fileDescriptor_503099fd3bb02aa5, []int{1} +} +func (m *EventRedeem) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *EventRedeem) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_EventRedeem.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 *EventRedeem) XXX_Merge(src proto.Message) { + xxx_messageInfo_EventRedeem.Merge(m, src) +} +func (m *EventRedeem) XXX_Size() int { + return m.Size() +} +func (m *EventRedeem) XXX_DiscardUnknown() { + xxx_messageInfo_EventRedeem.DiscardUnknown(m) +} + +var xxx_messageInfo_EventRedeem proto.InternalMessageInfo + +// EventRebalancing is emitted when a reserve re-balancing occurs. +type EventRebalancing struct { + // RebalancingResults of every asset in every Index. + Results []RebalancingResult `protobuf:"bytes,1,rep,name=results,proto3" json:"results"` +} + +func (m *EventRebalancing) Reset() { *m = EventRebalancing{} } +func (m *EventRebalancing) String() string { return proto.CompactTextString(m) } +func (*EventRebalancing) ProtoMessage() {} +func (*EventRebalancing) Descriptor() ([]byte, []int) { + return fileDescriptor_503099fd3bb02aa5, []int{2} +} +func (m *EventRebalancing) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *EventRebalancing) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_EventRebalancing.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 *EventRebalancing) XXX_Merge(src proto.Message) { + xxx_messageInfo_EventRebalancing.Merge(m, src) +} +func (m *EventRebalancing) XXX_Size() int { + return m.Size() +} +func (m *EventRebalancing) XXX_DiscardUnknown() { + xxx_messageInfo_EventRebalancing.DiscardUnknown(m) +} + +var xxx_messageInfo_EventRebalancing proto.InternalMessageInfo + +// RebalancingResult of a specific Index with initial and result balances of underlying assets. +type RebalancingResult struct { + MetokenDenom string `protobuf:"bytes,1,opt,name=metoken_denom,json=metokenDenom,proto3" json:"metoken_denom,omitempty"` + //Initial balance of an asset in the Index before re-balancing. + InitialBalance []types.Coin `protobuf:"bytes,2,rep,name=initial_balance,json=initialBalance,proto3" json:"initial_balance"` + // Result balance of an asset in the Index after re-balancing. + ResultBalance []types.Coin `protobuf:"bytes,3,rep,name=result_balance,json=resultBalance,proto3" json:"result_balance"` +} + +func (m *RebalancingResult) Reset() { *m = RebalancingResult{} } +func (m *RebalancingResult) String() string { return proto.CompactTextString(m) } +func (*RebalancingResult) ProtoMessage() {} +func (*RebalancingResult) Descriptor() ([]byte, []int) { + return fileDescriptor_503099fd3bb02aa5, []int{3} +} +func (m *RebalancingResult) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RebalancingResult) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RebalancingResult.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 *RebalancingResult) XXX_Merge(src proto.Message) { + xxx_messageInfo_RebalancingResult.Merge(m, src) +} +func (m *RebalancingResult) XXX_Size() int { + return m.Size() +} +func (m *RebalancingResult) XXX_DiscardUnknown() { + xxx_messageInfo_RebalancingResult.DiscardUnknown(m) +} + +var xxx_messageInfo_RebalancingResult proto.InternalMessageInfo + +// EventInterestClaim is emitted when the accrued interest was claimed from x/leverage +type EventInterestClaim struct { + // The denom and amount of successfully claimed interest + ClaimedAsset []types.Coin `protobuf:"bytes,1,rep,name=claimed_asset,json=claimedAsset,proto3" json:"claimed_asset"` +} + +func (m *EventInterestClaim) Reset() { *m = EventInterestClaim{} } +func (m *EventInterestClaim) String() string { return proto.CompactTextString(m) } +func (*EventInterestClaim) ProtoMessage() {} +func (*EventInterestClaim) Descriptor() ([]byte, []int) { + return fileDescriptor_503099fd3bb02aa5, []int{4} +} +func (m *EventInterestClaim) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *EventInterestClaim) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_EventInterestClaim.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 *EventInterestClaim) XXX_Merge(src proto.Message) { + xxx_messageInfo_EventInterestClaim.Merge(m, src) +} +func (m *EventInterestClaim) XXX_Size() int { + return m.Size() +} +func (m *EventInterestClaim) XXX_DiscardUnknown() { + xxx_messageInfo_EventInterestClaim.DiscardUnknown(m) +} + +var xxx_messageInfo_EventInterestClaim proto.InternalMessageInfo + +func init() { + proto.RegisterType((*EventSwap)(nil), "umeenetwork.umee.metoken.v1.EventSwap") + proto.RegisterType((*EventRedeem)(nil), "umeenetwork.umee.metoken.v1.EventRedeem") + proto.RegisterType((*EventRebalancing)(nil), "umeenetwork.umee.metoken.v1.EventRebalancing") + proto.RegisterType((*RebalancingResult)(nil), "umeenetwork.umee.metoken.v1.RebalancingResult") + proto.RegisterType((*EventInterestClaim)(nil), "umeenetwork.umee.metoken.v1.EventInterestClaim") +} + +func init() { proto.RegisterFile("umee/metoken/v1/events.proto", fileDescriptor_503099fd3bb02aa5) } + +var fileDescriptor_503099fd3bb02aa5 = []byte{ + // 479 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x94, 0xcd, 0x6e, 0x13, 0x31, + 0x14, 0x85, 0xc7, 0x99, 0x42, 0x15, 0xa7, 0x29, 0x60, 0x75, 0x31, 0x2d, 0x68, 0x88, 0xc2, 0x26, + 0x2c, 0x6a, 0x6b, 0x8a, 0x8a, 0xc4, 0xb2, 0x69, 0xf9, 0xdb, 0xb0, 0x98, 0xee, 0xba, 0x89, 0xe6, + 0xe7, 0x32, 0x58, 0xcd, 0xd8, 0xd1, 0xd8, 0x99, 0xf2, 0x18, 0x3c, 0x0c, 0x0f, 0x11, 0xb1, 0xaa, + 0x58, 0xb1, 0x42, 0x90, 0x6c, 0x10, 0x4f, 0x81, 0x3c, 0x76, 0x4a, 0x25, 0x24, 0x9a, 0x66, 0x67, + 0xfb, 0x9e, 0xef, 0xf8, 0x9e, 0xeb, 0x64, 0xf0, 0xa3, 0x69, 0x09, 0xc0, 0x4a, 0xd0, 0xf2, 0x1c, + 0x04, 0xab, 0x23, 0x06, 0x35, 0x08, 0xad, 0xe8, 0xa4, 0x92, 0x5a, 0x92, 0x87, 0xa6, 0x2a, 0x40, + 0x5f, 0xc8, 0xea, 0x9c, 0x9a, 0x35, 0x75, 0x4a, 0x5a, 0x47, 0x7b, 0x3b, 0x85, 0x2c, 0x64, 0xa3, + 0x63, 0x66, 0x65, 0x91, 0xbd, 0xdd, 0x4c, 0xaa, 0x52, 0xaa, 0x91, 0x2d, 0xd8, 0x8d, 0x2b, 0x85, + 0x76, 0xc7, 0xd2, 0x44, 0x01, 0xab, 0xa3, 0x14, 0x74, 0x12, 0xb1, 0x4c, 0x72, 0x61, 0xeb, 0xfd, + 0x5f, 0x08, 0xb7, 0x5f, 0x9a, 0xeb, 0x4f, 0x2f, 0x92, 0x09, 0x79, 0x8e, 0xdb, 0x15, 0x64, 0x7c, + 0xc2, 0x41, 0xe8, 0x00, 0xf5, 0xd0, 0xa0, 0x3d, 0x0c, 0xbe, 0x7e, 0xde, 0xdf, 0x71, 0x96, 0x47, + 0x79, 0x5e, 0x81, 0x52, 0xa7, 0xba, 0xe2, 0xa2, 0x88, 0xff, 0x4a, 0xc9, 0x21, 0xbe, 0x93, 0x28, + 0x05, 0x3a, 0x68, 0xf5, 0xd0, 0xa0, 0x73, 0xb0, 0x4b, 0x1d, 0x60, 0x6e, 0xa5, 0xee, 0x56, 0x7a, + 0x2c, 0xb9, 0x18, 0x6e, 0xcc, 0xbe, 0x3f, 0xf6, 0x62, 0xab, 0x26, 0x2f, 0xf0, 0xa6, 0xcb, 0x16, + 0xf8, 0xab, 0x81, 0x4b, 0x3d, 0x89, 0xb0, 0xff, 0x1e, 0x20, 0xd8, 0x58, 0x0d, 0x33, 0xda, 0xfe, + 0x6f, 0x84, 0x3b, 0x4d, 0xd4, 0x18, 0x72, 0x80, 0x72, 0xed, 0xb0, 0xd7, 0xba, 0x6e, 0xdd, 0xb2, + 0xeb, 0xab, 0x39, 0xf9, 0xb7, 0x9a, 0xd3, 0x1a, 0x61, 0x53, 0x7c, 0xdf, 0x65, 0x4d, 0x93, 0x71, + 0x22, 0x32, 0x2e, 0x0a, 0xf2, 0x0e, 0x6f, 0x56, 0xa0, 0xa6, 0x63, 0xad, 0x02, 0xd4, 0xf3, 0x07, + 0x9d, 0x03, 0x4a, 0xff, 0xf3, 0x5b, 0xa3, 0xd7, 0xd0, 0xb8, 0xc1, 0x96, 0x69, 0x9c, 0x49, 0xff, + 0x0b, 0xc2, 0x0f, 0xfe, 0x11, 0x91, 0x27, 0xb8, 0xeb, 0x4c, 0x46, 0x39, 0x08, 0x59, 0xda, 0xd1, + 0xc6, 0x5b, 0xee, 0xf0, 0xc4, 0x9c, 0x91, 0x37, 0xf8, 0x1e, 0x17, 0x5c, 0xf3, 0x64, 0x3c, 0xb2, + 0x3c, 0x04, 0xad, 0xa6, 0xa5, 0x1b, 0xd3, 0x6d, 0x3b, 0x6e, 0x68, 0x31, 0xf2, 0x0a, 0x6f, 0xdb, + 0x7e, 0xae, 0x8c, 0xfc, 0xd5, 0x8c, 0xba, 0x16, 0x73, 0x3e, 0xfd, 0x33, 0x4c, 0x9a, 0x81, 0xbd, + 0x15, 0x1a, 0x2a, 0x50, 0xfa, 0x78, 0x9c, 0xf0, 0x92, 0x9c, 0xe0, 0x6e, 0x66, 0x16, 0x90, 0x8f, + 0xec, 0xc3, 0xa1, 0xd5, 0xcc, 0xb7, 0x1c, 0x75, 0x64, 0xa0, 0xe1, 0xeb, 0xd9, 0xcf, 0xd0, 0x9b, + 0xcd, 0x43, 0x74, 0x39, 0x0f, 0xd1, 0x8f, 0x79, 0x88, 0x3e, 0x2d, 0x42, 0xef, 0x72, 0x11, 0x7a, + 0xdf, 0x16, 0xa1, 0x77, 0xf6, 0xb4, 0xe0, 0xfa, 0xc3, 0x34, 0xa5, 0x99, 0x2c, 0x99, 0x79, 0x83, + 0x7d, 0xf7, 0x20, 0xcd, 0x86, 0xd5, 0x87, 0xec, 0xe3, 0xf2, 0x5b, 0x91, 0xde, 0x6d, 0xfe, 0xb4, + 0xcf, 0xfe, 0x04, 0x00, 0x00, 0xff, 0xff, 0x4c, 0xbc, 0x6e, 0x0f, 0x42, 0x04, 0x00, 0x00, +} + +func (m *EventSwap) 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 *EventSwap) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *EventSwap) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Fee.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvents(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + { + size, err := m.Metoken.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvents(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + { + size, err := m.Asset.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvents(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Recipient) > 0 { + i -= len(m.Recipient) + copy(dAtA[i:], m.Recipient) + i = encodeVarintEvents(dAtA, i, uint64(len(m.Recipient))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *EventRedeem) 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 *EventRedeem) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *EventRedeem) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Fee.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvents(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + { + size, err := m.Asset.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvents(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + { + size, err := m.Metoken.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvents(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Recipient) > 0 { + i -= len(m.Recipient) + copy(dAtA[i:], m.Recipient) + i = encodeVarintEvents(dAtA, i, uint64(len(m.Recipient))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *EventRebalancing) 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 *EventRebalancing) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *EventRebalancing) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Results) > 0 { + for iNdEx := len(m.Results) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Results[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvents(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *RebalancingResult) 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 *RebalancingResult) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RebalancingResult) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ResultBalance) > 0 { + for iNdEx := len(m.ResultBalance) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.ResultBalance[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvents(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.InitialBalance) > 0 { + for iNdEx := len(m.InitialBalance) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.InitialBalance[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvents(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.MetokenDenom) > 0 { + i -= len(m.MetokenDenom) + copy(dAtA[i:], m.MetokenDenom) + i = encodeVarintEvents(dAtA, i, uint64(len(m.MetokenDenom))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *EventInterestClaim) 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 *EventInterestClaim) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *EventInterestClaim) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ClaimedAsset) > 0 { + for iNdEx := len(m.ClaimedAsset) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.ClaimedAsset[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvents(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintEvents(dAtA []byte, offset int, v uint64) int { + offset -= sovEvents(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *EventSwap) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Recipient) + if l > 0 { + n += 1 + l + sovEvents(uint64(l)) + } + l = m.Asset.Size() + n += 1 + l + sovEvents(uint64(l)) + l = m.Metoken.Size() + n += 1 + l + sovEvents(uint64(l)) + l = m.Fee.Size() + n += 1 + l + sovEvents(uint64(l)) + return n +} + +func (m *EventRedeem) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Recipient) + if l > 0 { + n += 1 + l + sovEvents(uint64(l)) + } + l = m.Metoken.Size() + n += 1 + l + sovEvents(uint64(l)) + l = m.Asset.Size() + n += 1 + l + sovEvents(uint64(l)) + l = m.Fee.Size() + n += 1 + l + sovEvents(uint64(l)) + return n +} + +func (m *EventRebalancing) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Results) > 0 { + for _, e := range m.Results { + l = e.Size() + n += 1 + l + sovEvents(uint64(l)) + } + } + return n +} + +func (m *RebalancingResult) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.MetokenDenom) + if l > 0 { + n += 1 + l + sovEvents(uint64(l)) + } + if len(m.InitialBalance) > 0 { + for _, e := range m.InitialBalance { + l = e.Size() + n += 1 + l + sovEvents(uint64(l)) + } + } + if len(m.ResultBalance) > 0 { + for _, e := range m.ResultBalance { + l = e.Size() + n += 1 + l + sovEvents(uint64(l)) + } + } + return n +} + +func (m *EventInterestClaim) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.ClaimedAsset) > 0 { + for _, e := range m.ClaimedAsset { + l = e.Size() + n += 1 + l + sovEvents(uint64(l)) + } + } + return n +} + +func sovEvents(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozEvents(x uint64) (n int) { + return sovEvents(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *EventSwap) 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 ErrIntOverflowEvents + } + 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: EventSwap: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: EventSwap: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Recipient", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Recipient = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Asset", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Asset.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Metoken", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Metoken.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Fee", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Fee.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEvents(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvents + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *EventRedeem) 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 ErrIntOverflowEvents + } + 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: EventRedeem: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: EventRedeem: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Recipient", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Recipient = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Metoken", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Metoken.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Asset", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Asset.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Fee", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Fee.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEvents(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvents + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *EventRebalancing) 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 ErrIntOverflowEvents + } + 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: EventRebalancing: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: EventRebalancing: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Results", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Results = append(m.Results, RebalancingResult{}) + if err := m.Results[len(m.Results)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEvents(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvents + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RebalancingResult) 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 ErrIntOverflowEvents + } + 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: RebalancingResult: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RebalancingResult: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MetokenDenom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.MetokenDenom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InitialBalance", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.InitialBalance = append(m.InitialBalance, types.Coin{}) + if err := m.InitialBalance[len(m.InitialBalance)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ResultBalance", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ResultBalance = append(m.ResultBalance, types.Coin{}) + if err := m.ResultBalance[len(m.ResultBalance)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEvents(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvents + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *EventInterestClaim) 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 ErrIntOverflowEvents + } + 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: EventInterestClaim: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: EventInterestClaim: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ClaimedAsset", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ClaimedAsset = append(m.ClaimedAsset, types.Coin{}) + if err := m.ClaimedAsset[len(m.ClaimedAsset)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEvents(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvents + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipEvents(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowEvents + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowEvents + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowEvents + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthEvents + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupEvents + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthEvents + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthEvents = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowEvents = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupEvents = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/metoken/expected_keepers.go b/x/metoken/expected_keepers.go new file mode 100644 index 0000000000..a3ce21c9e2 --- /dev/null +++ b/x/metoken/expected_keepers.go @@ -0,0 +1,36 @@ +package metoken + +import ( + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + ltypes "github.com/umee-network/umee/v5/x/leverage/types" + otypes "github.com/umee-network/umee/v5/x/oracle/types" +) + +// BankKeeper defines the expected x/bank keeper interface. +type BankKeeper interface { + MintCoins(ctx sdk.Context, moduleName string, amounts sdk.Coins) error + BurnCoins(ctx sdk.Context, moduleName string, amounts sdk.Coins) error + SendCoinsFromModuleToAccount( + ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins, + ) error + SendCoinsFromAccountToModule( + ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins, + ) error +} + +// LeverageKeeper interface for interacting with x/leverage +type LeverageKeeper interface { + GetTokenSettings(ctx sdk.Context, denom string) (ltypes.Token, error) + ExchangeToken(ctx sdk.Context, token sdk.Coin) (sdk.Coin, error) + ExchangeUToken(ctx sdk.Context, uToken sdk.Coin) (sdk.Coin, error) + Supply(ctx sdk.Context, supplierAddr sdk.AccAddress, coin sdk.Coin) (sdk.Coin, error) + Withdraw(ctx sdk.Context, supplierAddr sdk.AccAddress, uToken sdk.Coin) (sdk.Coin, bool, error) + ModuleMaxWithdraw(ctx sdk.Context, spendableUTokens sdk.Coin) (sdkmath.Int, error) + GetTotalSupply(ctx sdk.Context, denom string) (sdk.Coin, error) +} + +// OracleKeeper interface for price feed. +type OracleKeeper interface { + AllMedianPrices(ctx sdk.Context) otypes.Prices +} diff --git a/x/metoken/genesis.go b/x/metoken/genesis.go new file mode 100644 index 0000000000..abff142687 --- /dev/null +++ b/x/metoken/genesis.go @@ -0,0 +1,164 @@ +package metoken + +import ( + "fmt" + "time" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// NewGenesisState creates a new GenesisState object +func NewGenesisState( + params Params, + registry []Index, + balances []IndexBalances, + nextRebalancingTime time.Time, + nextInterestClaimTime time.Time, +) *GenesisState { + return &GenesisState{ + Params: params, + Registry: registry, + Balances: balances, + NextRebalancingTime: nextRebalancingTime, + NextInterestClaimTime: nextInterestClaimTime, + } +} + +// DefaultGenesisState creates a new default GenesisState object +func DefaultGenesisState() *GenesisState { + return &GenesisState{ + Params: DefaultParams(), + Registry: nil, + Balances: nil, + NextRebalancingTime: time.Time{}, + NextInterestClaimTime: time.Time{}, + } +} + +// Validate perform basic validation of the GenesisState +func (gs GenesisState) Validate() error { + for _, index := range gs.Registry { + if err := index.Validate(); err != nil { + return err + } + } + + for _, balance := range gs.Balances { + if err := balance.Validate(); err != nil { + return err + } + } + + return nil +} + +// NewIndexBalances creates a new IndexBalances object. +func NewIndexBalances(meTokenSupply sdk.Coin, assetBalances []AssetBalance) IndexBalances { + return IndexBalances{ + MetokenSupply: meTokenSupply, + AssetBalances: assetBalances, + } +} + +// Validate perform basic validation of the IndexBalances +func (ib IndexBalances) Validate() error { + if !IsMeToken(ib.MetokenSupply.Denom) { + return sdkerrors.ErrInvalidRequest.Wrapf( + "meToken denom %s should have the following format: me/", + ib.MetokenSupply.Denom, + ) + } + + if err := ib.MetokenSupply.Validate(); err != nil { + return err + } + + existingBalances := make(map[string]struct{}) + for _, balance := range ib.AssetBalances { + if _, present := existingBalances[balance.Denom]; present { + return fmt.Errorf("duplicated balance %s in the Index: %s", balance.Denom, ib.MetokenSupply.Denom) + } + existingBalances[balance.Denom] = struct{}{} + + if err := balance.Validate(); err != nil { + return err + } + } + + return nil +} + +// AssetBalance returns an asset balance and its index from balances, given a specific denom. +// If it isn't present, -1 as index. +func (ib IndexBalances) AssetBalance(denom string) (int, AssetBalance) { + for i, balance := range ib.AssetBalances { + if balance.Denom == denom { + return i, balance + } + } + + return -1, AssetBalance{} +} + +// SetAssetBalance overrides an asset balance if exists in the list, otherwise add it to the list. +func (ib IndexBalances) SetAssetBalance(balance AssetBalance) { + i, _ := ib.AssetBalance(balance.Denom) + + if i < 0 { + ib.AssetBalances = append(ib.AssetBalances, balance) + return + } + + ib.AssetBalances[i] = balance + +} + +// NewZeroAssetBalance creates a new AssetBalance object with all balances in zero. +func NewZeroAssetBalance(denom string) AssetBalance { + return AssetBalance{ + Denom: denom, + Leveraged: sdkmath.ZeroInt(), + Reserved: sdkmath.ZeroInt(), + Fees: sdkmath.ZeroInt(), + Interest: sdkmath.ZeroInt(), + } +} + +// NewAssetBalance creates a new AssetBalance object. +func NewAssetBalance(denom string, inLeverage, inReserves, inFees, inInterest sdkmath.Int) AssetBalance { + return AssetBalance{ + Denom: denom, + Leveraged: inLeverage, + Reserved: inReserves, + Fees: inFees, + Interest: inInterest, + } +} + +// Validate perform basic validation of the AssetBalance +func (ab AssetBalance) Validate() error { + if err := sdk.ValidateDenom(ab.Denom); err != nil { + return err + } + if ab.Leveraged.IsNegative() { + return sdkerrors.ErrInvalidRequest.Wrapf("leveraged asset balance cannot be negative") + } + if ab.Reserved.IsNegative() { + return sdkerrors.ErrInvalidRequest.Wrapf("reserved asset balance cannot be negative") + } + if ab.Fees.IsNegative() { + return sdkerrors.ErrInvalidRequest.Wrapf("fees asset balance cannot be negative") + } + if ab.Interest.IsNegative() { + return sdkerrors.ErrInvalidRequest.Wrapf("interest asset balance cannot be negative") + } + + return nil +} + +// AvailableSupply returns reserved plus leveraged +func (ab AssetBalance) AvailableSupply() sdkmath.Int { + return ab.Reserved.Add(ab.Leveraged) +} diff --git a/x/metoken/genesis.pb.go b/x/metoken/genesis.pb.go new file mode 100644 index 0000000000..84223487ff --- /dev/null +++ b/x/metoken/genesis.pb.go @@ -0,0 +1,1169 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: umee/metoken/v1/genesis.proto + +package metoken + +import ( + cosmossdk_io_math "cosmossdk.io/math" + fmt "fmt" + types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" + _ "google.golang.org/protobuf/types/known/timestamppb" + io "io" + math "math" + math_bits "math/bits" + time "time" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf +var _ = time.Kitchen + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// GenesisState defines the x/metoken module's genesis state. +type GenesisState struct { + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` + Registry []Index `protobuf:"bytes,2,rep,name=registry,proto3" json:"registry"` + Balances []IndexBalances `protobuf:"bytes,3,rep,name=balances,proto3" json:"balances"` + NextRebalancingTime time.Time `protobuf:"bytes,4,opt,name=next_rebalancing_time,json=nextRebalancingTime,proto3,stdtime" json:"next_rebalancing_time"` + NextInterestClaimTime time.Time `protobuf:"bytes,5,opt,name=next_interest_claim_time,json=nextInterestClaimTime,proto3,stdtime" json:"next_interest_claim_time"` +} + +func (m *GenesisState) Reset() { *m = GenesisState{} } +func (m *GenesisState) String() string { return proto.CompactTextString(m) } +func (*GenesisState) ProtoMessage() {} +func (*GenesisState) Descriptor() ([]byte, []int) { + return fileDescriptor_5df2a396d6481bf7, []int{0} +} +func (m *GenesisState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisState.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 *GenesisState) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisState.Merge(m, src) +} +func (m *GenesisState) XXX_Size() int { + return m.Size() +} +func (m *GenesisState) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisState.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisState proto.InternalMessageInfo + +func (m *GenesisState) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +func (m *GenesisState) GetRegistry() []Index { + if m != nil { + return m.Registry + } + return nil +} + +func (m *GenesisState) GetBalances() []IndexBalances { + if m != nil { + return m.Balances + } + return nil +} + +func (m *GenesisState) GetNextRebalancingTime() time.Time { + if m != nil { + return m.NextRebalancingTime + } + return time.Time{} +} + +func (m *GenesisState) GetNextInterestClaimTime() time.Time { + if m != nil { + return m.NextInterestClaimTime + } + return time.Time{} +} + +// IndexBalances is the state of an Index, containing its meToken supply and all underlying asset balances. +type IndexBalances struct { + MetokenSupply types.Coin `protobuf:"bytes,1,opt,name=metoken_supply,json=metokenSupply,proto3" json:"metoken_supply"` + AssetBalances []AssetBalance `protobuf:"bytes,2,rep,name=asset_balances,json=assetBalances,proto3" json:"asset_balances"` +} + +func (m *IndexBalances) Reset() { *m = IndexBalances{} } +func (m *IndexBalances) String() string { return proto.CompactTextString(m) } +func (*IndexBalances) ProtoMessage() {} +func (*IndexBalances) Descriptor() ([]byte, []int) { + return fileDescriptor_5df2a396d6481bf7, []int{1} +} +func (m *IndexBalances) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *IndexBalances) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_IndexBalances.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 *IndexBalances) XXX_Merge(src proto.Message) { + xxx_messageInfo_IndexBalances.Merge(m, src) +} +func (m *IndexBalances) XXX_Size() int { + return m.Size() +} +func (m *IndexBalances) XXX_DiscardUnknown() { + xxx_messageInfo_IndexBalances.DiscardUnknown(m) +} + +var xxx_messageInfo_IndexBalances proto.InternalMessageInfo + +func (m *IndexBalances) GetMetokenSupply() types.Coin { + if m != nil { + return m.MetokenSupply + } + return types.Coin{} +} + +func (m *IndexBalances) GetAssetBalances() []AssetBalance { + if m != nil { + return m.AssetBalances + } + return nil +} + +// AssetBalance tracks how much of a single asset is held in leverage, reserves, fees and interest account. +type AssetBalance struct { + Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty"` + Leveraged cosmossdk_io_math.Int `protobuf:"bytes,2,opt,name=leveraged,proto3,customtype=cosmossdk.io/math.Int" json:"leveraged"` + Reserved cosmossdk_io_math.Int `protobuf:"bytes,3,opt,name=reserved,proto3,customtype=cosmossdk.io/math.Int" json:"reserved"` + Fees cosmossdk_io_math.Int `protobuf:"bytes,4,opt,name=fees,proto3,customtype=cosmossdk.io/math.Int" json:"fees"` + Interest cosmossdk_io_math.Int `protobuf:"bytes,5,opt,name=interest,proto3,customtype=cosmossdk.io/math.Int" json:"interest"` +} + +func (m *AssetBalance) Reset() { *m = AssetBalance{} } +func (m *AssetBalance) String() string { return proto.CompactTextString(m) } +func (*AssetBalance) ProtoMessage() {} +func (*AssetBalance) Descriptor() ([]byte, []int) { + return fileDescriptor_5df2a396d6481bf7, []int{2} +} +func (m *AssetBalance) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AssetBalance) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AssetBalance.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 *AssetBalance) XXX_Merge(src proto.Message) { + xxx_messageInfo_AssetBalance.Merge(m, src) +} +func (m *AssetBalance) XXX_Size() int { + return m.Size() +} +func (m *AssetBalance) XXX_DiscardUnknown() { + xxx_messageInfo_AssetBalance.DiscardUnknown(m) +} + +var xxx_messageInfo_AssetBalance proto.InternalMessageInfo + +func (m *AssetBalance) GetDenom() string { + if m != nil { + return m.Denom + } + return "" +} + +func init() { + proto.RegisterType((*GenesisState)(nil), "umeenetwork.umee.metoken.v1.GenesisState") + proto.RegisterType((*IndexBalances)(nil), "umeenetwork.umee.metoken.v1.IndexBalances") + proto.RegisterType((*AssetBalance)(nil), "umeenetwork.umee.metoken.v1.AssetBalance") +} + +func init() { proto.RegisterFile("umee/metoken/v1/genesis.proto", fileDescriptor_5df2a396d6481bf7) } + +var fileDescriptor_5df2a396d6481bf7 = []byte{ + // 553 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x93, 0x4f, 0x6e, 0x13, 0x31, + 0x14, 0xc6, 0x33, 0x4d, 0x5a, 0xa5, 0xee, 0x9f, 0x85, 0x69, 0xa5, 0x21, 0xa8, 0x93, 0x2a, 0x6c, + 0x5a, 0x24, 0x6c, 0xa5, 0x88, 0x05, 0x62, 0xd5, 0x04, 0x81, 0x22, 0xb1, 0x40, 0x29, 0x42, 0x08, + 0x09, 0x45, 0x9e, 0xe4, 0x75, 0x6a, 0x25, 0xb6, 0xa3, 0xb1, 0x33, 0xa4, 0x57, 0x60, 0xd5, 0x13, + 0x70, 0x05, 0xae, 0xd1, 0x65, 0x97, 0x88, 0x45, 0x41, 0xc9, 0x45, 0x90, 0x3d, 0x9e, 0xb4, 0x08, + 0x29, 0x2d, 0xbb, 0xb1, 0xfd, 0x7d, 0x3f, 0x3f, 0x7f, 0xef, 0x0d, 0xda, 0x9b, 0x08, 0x00, 0x2a, + 0xc0, 0xa8, 0x21, 0x48, 0x9a, 0x35, 0x69, 0x02, 0x12, 0x34, 0xd7, 0x64, 0x9c, 0x2a, 0xa3, 0xf0, + 0x23, 0x7b, 0x2c, 0xc1, 0x7c, 0x51, 0xe9, 0x90, 0xd8, 0x6f, 0xe2, 0xa5, 0x24, 0x6b, 0xd6, 0xa2, + 0xbe, 0xd2, 0x42, 0x69, 0x1a, 0x33, 0x0d, 0x34, 0x6b, 0xc6, 0x60, 0x58, 0x93, 0xf6, 0x15, 0x97, + 0xb9, 0xb9, 0xb6, 0x93, 0xa8, 0x44, 0xb9, 0x4f, 0x6a, 0xbf, 0xfc, 0x6e, 0x3d, 0x51, 0x2a, 0x19, + 0x01, 0x75, 0xab, 0x78, 0x72, 0x4a, 0x0d, 0x17, 0xa0, 0x0d, 0x13, 0x63, 0x2f, 0xf8, 0xa7, 0xa4, + 0xe2, 0x4a, 0x77, 0xdc, 0xf8, 0x56, 0x46, 0x9b, 0x6f, 0xf2, 0x22, 0x4f, 0x0c, 0x33, 0x80, 0x8f, + 0xd1, 0xda, 0x98, 0xa5, 0x4c, 0xe8, 0x30, 0xd8, 0x0f, 0x0e, 0x36, 0x8e, 0x1e, 0x93, 0x25, 0x45, + 0x93, 0x77, 0x4e, 0xda, 0xaa, 0x5c, 0x5e, 0xd7, 0x4b, 0x5d, 0x6f, 0xc4, 0xaf, 0x50, 0x35, 0x85, + 0x84, 0x6b, 0x93, 0x9e, 0x87, 0x2b, 0xfb, 0xe5, 0x83, 0x8d, 0xa3, 0xc6, 0x52, 0x48, 0x47, 0x0e, + 0x60, 0xea, 0x19, 0x0b, 0x27, 0x7e, 0x8b, 0xaa, 0x31, 0x1b, 0x31, 0xd9, 0x07, 0x1d, 0x96, 0x1d, + 0xe5, 0xc9, 0x3d, 0x28, 0xde, 0x51, 0xd0, 0x0a, 0x02, 0xfe, 0x88, 0x76, 0x25, 0x4c, 0x4d, 0x2f, + 0x85, 0x7c, 0x8b, 0xcb, 0xa4, 0x67, 0xa3, 0x0a, 0x2b, 0xee, 0x95, 0x35, 0x92, 0xe7, 0x48, 0x8a, + 0x1c, 0xc9, 0xfb, 0x22, 0xc7, 0x56, 0xd5, 0xa2, 0x2e, 0x7e, 0xd5, 0x83, 0xee, 0x03, 0x8b, 0xe8, + 0xde, 0x10, 0xac, 0x06, 0x7f, 0x46, 0xa1, 0x23, 0x73, 0x69, 0x20, 0x05, 0x6d, 0x7a, 0xfd, 0x11, + 0xe3, 0x22, 0x87, 0xaf, 0xfe, 0x07, 0xdc, 0xd5, 0xd7, 0xf1, 0x90, 0xb6, 0x65, 0x58, 0x55, 0xe3, + 0x7b, 0x80, 0xb6, 0xfe, 0x7a, 0x1a, 0x7e, 0x8d, 0xb6, 0xfd, 0xb3, 0x7b, 0x7a, 0x32, 0x1e, 0x8f, + 0xce, 0x7d, 0xa7, 0x1e, 0x92, 0x7c, 0x82, 0x88, 0x9d, 0x20, 0xe2, 0x27, 0x88, 0xb4, 0x15, 0x97, + 0x3e, 0x8d, 0x2d, 0x6f, 0x3b, 0x71, 0x2e, 0xfc, 0x01, 0x6d, 0x33, 0xad, 0xc1, 0xf4, 0x16, 0x31, + 0xe7, 0xcd, 0x3a, 0x5c, 0x1a, 0xf3, 0xb1, 0xb5, 0xf8, 0x5a, 0x0a, 0x2e, 0xbb, 0xb5, 0xa7, 0x1b, + 0x5f, 0x57, 0xd0, 0xe6, 0x6d, 0x15, 0xde, 0x41, 0xab, 0x03, 0x90, 0x4a, 0xb8, 0x3a, 0xd7, 0xbb, + 0xf9, 0x02, 0xbf, 0x44, 0xeb, 0x23, 0xc8, 0x20, 0x65, 0x09, 0x0c, 0xc2, 0x15, 0x7b, 0xd2, 0xda, + 0xb3, 0xb8, 0x9f, 0xd7, 0xf5, 0xdd, 0xfc, 0x21, 0x7a, 0x30, 0x24, 0x5c, 0x51, 0xc1, 0xcc, 0x19, + 0xe9, 0x48, 0xd3, 0xbd, 0xd1, 0xe3, 0x17, 0x76, 0xc4, 0x34, 0xa4, 0x19, 0x0c, 0xc2, 0xf2, 0x7d, + 0xbc, 0x0b, 0x39, 0x6e, 0xa2, 0xca, 0x29, 0x80, 0x76, 0x8d, 0xbf, 0xd3, 0xe6, 0xa4, 0xf6, 0xb6, + 0xa2, 0xbb, 0xae, 0xa5, 0x77, 0xdf, 0x56, 0xc8, 0x5b, 0xed, 0xcb, 0x59, 0x14, 0x5c, 0xcd, 0xa2, + 0xe0, 0xf7, 0x2c, 0x0a, 0x2e, 0xe6, 0x51, 0xe9, 0x6a, 0x1e, 0x95, 0x7e, 0xcc, 0xa3, 0xd2, 0xa7, + 0xc3, 0x84, 0x9b, 0xb3, 0x49, 0x4c, 0xfa, 0x4a, 0x50, 0x1b, 0xf2, 0x53, 0x9f, 0xb8, 0x5b, 0xd0, + 0xec, 0x39, 0x9d, 0x16, 0xbf, 0x6a, 0xbc, 0xe6, 0x06, 0xe7, 0xd9, 0x9f, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x29, 0x77, 0x0b, 0x39, 0x5f, 0x04, 0x00, 0x00, +} + +func (m *GenesisState) 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 *GenesisState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + n1, err1 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.NextInterestClaimTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.NextInterestClaimTime):]) + if err1 != nil { + return 0, err1 + } + i -= n1 + i = encodeVarintGenesis(dAtA, i, uint64(n1)) + i-- + dAtA[i] = 0x2a + n2, err2 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.NextRebalancingTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.NextRebalancingTime):]) + if err2 != nil { + return 0, err2 + } + i -= n2 + i = encodeVarintGenesis(dAtA, i, uint64(n2)) + i-- + dAtA[i] = 0x22 + if len(m.Balances) > 0 { + for iNdEx := len(m.Balances) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Balances[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.Registry) > 0 { + for iNdEx := len(m.Registry) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Registry[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *IndexBalances) 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 *IndexBalances) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *IndexBalances) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.AssetBalances) > 0 { + for iNdEx := len(m.AssetBalances) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.AssetBalances[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + { + size, err := m.MetokenSupply.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *AssetBalance) 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 *AssetBalance) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AssetBalance) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.Interest.Size() + i -= size + if _, err := m.Interest.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + { + size := m.Fees.Size() + i -= size + if _, err := m.Fees.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + { + size := m.Reserved.Size() + i -= size + if _, err := m.Reserved.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + { + size := m.Leveraged.Size() + i -= size + if _, err := m.Leveraged.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.Denom))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { + offset -= sovGenesis(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *GenesisState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovGenesis(uint64(l)) + if len(m.Registry) > 0 { + for _, e := range m.Registry { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.Balances) > 0 { + for _, e := range m.Balances { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.NextRebalancingTime) + n += 1 + l + sovGenesis(uint64(l)) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.NextInterestClaimTime) + n += 1 + l + sovGenesis(uint64(l)) + return n +} + +func (m *IndexBalances) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.MetokenSupply.Size() + n += 1 + l + sovGenesis(uint64(l)) + if len(m.AssetBalances) > 0 { + for _, e := range m.AssetBalances { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + return n +} + +func (m *AssetBalance) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Denom) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = m.Leveraged.Size() + n += 1 + l + sovGenesis(uint64(l)) + l = m.Reserved.Size() + n += 1 + l + sovGenesis(uint64(l)) + l = m.Fees.Size() + n += 1 + l + sovGenesis(uint64(l)) + l = m.Interest.Size() + n += 1 + l + sovGenesis(uint64(l)) + return n +} + +func sovGenesis(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozGenesis(x uint64) (n int) { + return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *GenesisState) 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 ErrIntOverflowGenesis + } + 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: GenesisState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Registry", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Registry = append(m.Registry, Index{}) + if err := m.Registry[len(m.Registry)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Balances", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Balances = append(m.Balances, IndexBalances{}) + if err := m.Balances[len(m.Balances)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NextRebalancingTime", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.NextRebalancingTime, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NextInterestClaimTime", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.NextInterestClaimTime, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *IndexBalances) 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 ErrIntOverflowGenesis + } + 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: IndexBalances: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: IndexBalances: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MetokenSupply", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MetokenSupply.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AssetBalances", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AssetBalances = append(m.AssetBalances, AssetBalance{}) + if err := m.AssetBalances[len(m.AssetBalances)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AssetBalance) 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 ErrIntOverflowGenesis + } + 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: AssetBalance: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AssetBalance: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Leveraged", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Leveraged.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Reserved", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Reserved.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Fees", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Fees.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Interest", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Interest.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipGenesis(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthGenesis + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupGenesis + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthGenesis + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthGenesis = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGenesis = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupGenesis = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/metoken/genesis_test.go b/x/metoken/genesis_test.go new file mode 100644 index 0000000000..f77a87fdda --- /dev/null +++ b/x/metoken/genesis_test.go @@ -0,0 +1,167 @@ +package metoken + +import ( + "testing" + + "github.com/umee-network/umee/v5/util/coin" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + "gotest.tools/v3/assert" +) + +func TestGenesisState_Validate(t *testing.T) { + invalidRegistry := *DefaultGenesisState() + invalidRegistry.Registry = []Index{ + NewIndex("token", sdkmath.ZeroInt(), 6, Fee{}, nil), + } + + invalidBalance := *DefaultGenesisState() + invalidBalance.Balances = []IndexBalances{ + { + MetokenSupply: sdk.Coin{ + Denom: "test", + Amount: sdkmath.ZeroInt(), + }, + AssetBalances: nil, + }, + } + + tcs := []struct { + name string + g GenesisState + errMsg string + }{ + {"default genesis", *DefaultGenesisState(), ""}, + { + "invalid registry", + invalidRegistry, + "meToken denom token should have the following format: me/", + }, + { + "invalid balances", + invalidBalance, + "meToken denom test should have the following format: me/", + }, + } + + for _, tc := range tcs { + t.Run( + tc.name, func(t *testing.T) { + err := tc.g.Validate() + if tc.errMsg != "" { + assert.ErrorContains(t, err, tc.errMsg) + } else { + assert.NilError(t, err) + } + }, + ) + } +} + +func TestIndexBalances_Validate(t *testing.T) { + zeroInt := sdkmath.ZeroInt() + negativeIntOne := sdkmath.NewInt(-1) + + invalidMetokenDenom := validIndexBalances() + invalidMetokenDenom.MetokenSupply = sdk.NewCoin("test", sdkmath.ZeroInt()) + + invalidMetokenAmount := validIndexBalances() + invalidMetokenAmount.MetokenSupply = coin.Negative1("me/Token") + + invalidAssetInLeverage := validIndexBalances() + invalidAssetInLeverage.SetAssetBalance(NewAssetBalance("USDT", negativeIntOne, zeroInt, zeroInt, zeroInt)) + + invalidAssetInReserves := validIndexBalances() + invalidAssetInReserves.SetAssetBalance(NewAssetBalance("USDT", zeroInt, negativeIntOne, zeroInt, zeroInt)) + + invalidAssetInFees := validIndexBalances() + invalidAssetInFees.SetAssetBalance(NewAssetBalance("USDT", zeroInt, zeroInt, negativeIntOne, zeroInt)) + + invalidAssetInInterest := validIndexBalances() + invalidAssetInInterest.SetAssetBalance(NewAssetBalance("USDT", zeroInt, zeroInt, zeroInt, negativeIntOne)) + + duplicatedBalance := validIndexBalances() + duplicatedBalance.AssetBalances = append(duplicatedBalance.AssetBalances, NewZeroAssetBalance("USDT")) + + tcs := []struct { + name string + ib IndexBalances + errMsg string + }{ + {"valid index balance", validIndexBalances(), ""}, + { + "invalid meToken denom", + invalidMetokenDenom, + "meToken denom test should have the following format: me/", + }, + { + "invalid meToken amount", + invalidMetokenAmount, + "negative coin amount", + }, + { + "invalid assetInLeverage", + invalidAssetInLeverage, + "asset balance cannot be negative", + }, + { + "invalid assetInReserves", + invalidAssetInReserves, + "asset balance cannot be negative", + }, + { + "invalid assetInFee", + invalidAssetInFees, + "asset balance cannot be negative", + }, + { + "invalid assetInInterest", + invalidAssetInInterest, + "asset balance cannot be negative", + }, + { + "duplicated balance", + duplicatedBalance, + "duplicated balance", + }, + { + "valid index balance", + NewIndexBalances( + sdk.NewCoin("me/USD", sdkmath.ZeroInt()), []AssetBalance{ + NewZeroAssetBalance("USDT"), + }, + ), + "", + }, + } + + for _, tc := range tcs { + t.Run( + tc.name, func(t *testing.T) { + err := tc.ib.Validate() + if tc.errMsg != "" { + assert.ErrorContains(t, err, tc.errMsg) + } else { + assert.NilError(t, err) + } + }, + ) + } +} + +func validIndexBalances() IndexBalances { + zeroInt := sdkmath.ZeroInt() + return IndexBalances{ + MetokenSupply: coin.Zero("me/USD"), + AssetBalances: []AssetBalance{ + NewAssetBalance( + "USDT", + zeroInt, + zeroInt, + zeroInt, + zeroInt, + ), + }, + } +} diff --git a/x/metoken/index.go b/x/metoken/index.go new file mode 100644 index 0000000000..824e4ca230 --- /dev/null +++ b/x/metoken/index.go @@ -0,0 +1,202 @@ +package metoken + +import ( + "fmt" + "strings" + + sdkmath "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +const ( + // MeTokenPrefix defines the meToken denomination prefix for all meToken Indexes. + MeTokenPrefix = "me/" +) + +// IsMeToken detects the meToken prefix on a denom. +func IsMeToken(denom string) bool { + return strings.HasPrefix(denom, MeTokenPrefix) +} + +// NewIndex creates a new Index object +func NewIndex(denom string, maxSupply sdkmath.Int, exponent uint32, fee Fee, acceptedAssets []AcceptedAsset) Index { + return Index{ + Denom: denom, + MaxSupply: maxSupply, + Exponent: exponent, + Fee: fee, + AcceptedAssets: acceptedAssets, + } +} + +// Validate perform basic validation of the Index +func (i Index) Validate() error { + if !IsMeToken(i.Denom) { + return sdkerrors.ErrInvalidRequest.Wrapf( + "meToken denom %s should have the following format: me/", + i.Denom, + ) + } + + if i.MaxSupply.IsNegative() { + return sdkerrors.ErrInvalidRequest.Wrapf( + "maxSupply cannot be negative for %s", + i.Denom, + ) + } + + if err := i.Fee.Validate(); err != nil { + return err + } + + totalAllocation := sdk.ZeroDec() + existingAssets := make(map[string]struct{}) + for _, asset := range i.AcceptedAssets { + if _, present := existingAssets[asset.Denom]; present { + return fmt.Errorf("duplicated accepted asset %s in the Index: %s", asset.Denom, i.Denom) + } + existingAssets[asset.Denom] = struct{}{} + + if err := sdk.ValidateDenom(asset.Denom); err != nil { + return err + } + + if err := asset.Validate(); err != nil { + return err + } + totalAllocation = totalAllocation.Add(asset.TargetAllocation) + } + + if !totalAllocation.Equal(sdk.OneDec()) { + return sdkerrors.ErrInvalidRequest.Wrapf( + "total allocation %s of all the accepted assets should be 1.0", + totalAllocation.String(), + ) + } + + return nil +} + +// NewFee creates a new Fee object +func NewFee(minFee, balancedFee, maxFee sdk.Dec) Fee { + return Fee{ + MinFee: minFee, + BalancedFee: balancedFee, + MaxFee: maxFee, + } +} + +// Validate perform basic validation of the Fee +func (f Fee) Validate() error { + if f.MinFee.IsNegative() || f.MinFee.GT(sdk.OneDec()) { + return sdkerrors.ErrInvalidRequest.Wrapf("min_fee %s should be between 0.0 and 1.0", f.MinFee.String()) + } + + if f.BalancedFee.IsNegative() || f.BalancedFee.GT(sdk.OneDec()) { + return sdkerrors.ErrInvalidRequest.Wrapf( + "balanced_fee %s should be between 0.0 and 1.0", + f.BalancedFee.String(), + ) + } + + // BalancedFee must be always greater than MinFee for correct incentivizing and disincentivizing the allocation + // of every asset in the index + if f.BalancedFee.LTE(f.MinFee) { + return sdkerrors.ErrInvalidRequest.Wrapf( + "balanced_fee %s should be greater than min_fee %s", + f.BalancedFee.String(), f.MinFee.String(), + ) + } + + if f.MaxFee.IsNegative() || f.MaxFee.GT(sdk.OneDec()) { + return sdkerrors.ErrInvalidRequest.Wrapf("max_fee %s should be between 0.0 and 1.0", f.MaxFee.String()) + } + + // MaxFee must be always greater than BalancedFee for correct incentivizing and disincentivizing the allocation + // of every asset in the index + if f.MaxFee.LTE(f.BalancedFee) { + return sdkerrors.ErrInvalidRequest.Wrapf( + "max_fee %s should be greater than balanced_fee %s", + f.MaxFee.String(), f.BalancedFee.String(), + ) + } + + return nil +} + +// CalculateFee based on its settings and allocation deviation. +func (f Fee) CalculateFee(allocationDeviation sdk.Dec) sdk.Dec { + fee := allocationDeviation.Mul(f.BalancedFee).Add(f.BalancedFee) + + if fee.LT(f.MinFee) { + return f.MinFee + } + + if fee.GT(f.MaxFee) { + return f.MaxFee + } + + return fee +} + +// NewAcceptedAsset creates a new AcceptedAsset object +func NewAcceptedAsset(denom string, reservePortion, targetAllocation sdk.Dec) AcceptedAsset { + return AcceptedAsset{ + Denom: denom, + ReservePortion: reservePortion, + TargetAllocation: targetAllocation, + } +} + +// Validate perform basic validation of the AcceptedAsset +func (aa AcceptedAsset) Validate() error { + if aa.TargetAllocation.IsNegative() || aa.TargetAllocation.GT(sdk.OneDec()) { + return sdkerrors.ErrInvalidRequest.Wrapf( + "target_allocation %s should be between 0.0 and 1.0", + aa.TargetAllocation.String(), + ) + } + + if aa.ReservePortion.IsNegative() || aa.ReservePortion.GT(sdk.OneDec()) { + return sdkerrors.ErrInvalidRequest.Wrapf( + "reserve_portion %s should be between 0.0 and 1.0", + aa.ReservePortion.String(), + ) + } + + return nil +} + +// AcceptedAsset returns an accepted asset and its index in the list, given a specific denom. If it isn't present, +// returns -1. +func (i Index) AcceptedAsset(denom string) (int, AcceptedAsset) { + for index, aa := range i.AcceptedAssets { + if aa.Denom == denom { + return index, aa + } + } + return -1, AcceptedAsset{} +} + +// HasAcceptedAsset returns true if an accepted asset is present in the index. Otherwise returns false. +func (i Index) HasAcceptedAsset(denom string) bool { + for _, aa := range i.AcceptedAssets { + if aa.Denom == denom { + return true + } + } + return false +} + +// SetAcceptedAsset overrides an accepted asset if exists in the list, otherwise add it to the list. +func (i Index) SetAcceptedAsset(acceptedAsset AcceptedAsset) { + index, _ := i.AcceptedAsset(acceptedAsset.Denom) + if index > 0 { + i.AcceptedAssets = append(i.AcceptedAssets, acceptedAsset) + return + } + + i.AcceptedAssets[index] = acceptedAsset +} diff --git a/x/metoken/index_test.go b/x/metoken/index_test.go new file mode 100644 index 0000000000..dfc1f3d920 --- /dev/null +++ b/x/metoken/index_test.go @@ -0,0 +1,231 @@ +package metoken + +import ( + "testing" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + "gotest.tools/v3/assert" +) + +func TestIndex_Validate(t *testing.T) { + invalidMaxSupply := validIndex() + invalidMaxSupply.Denom = "me/USD" + invalidMaxSupply.MaxSupply = sdkmath.NewInt(-1) + + invalidFee := validIndex() + invalidFee.Fee = NewFee(sdk.MustNewDecFromStr("-1.0"), sdk.Dec{}, sdk.Dec{}) + + invalidDenomAcceptedAsset := validIndex() + invalidDenomAcceptedAsset.AcceptedAssets = []AcceptedAsset{ + NewAcceptedAsset("????", sdk.MustNewDecFromStr("-0.2"), sdk.MustNewDecFromStr("1.0")), + } + + invalidAcceptedAsset := validIndex() + invalidAcceptedAsset.AcceptedAssets = []AcceptedAsset{ + NewAcceptedAsset("USDT", sdk.MustNewDecFromStr("-0.2"), sdk.MustNewDecFromStr("1.0")), + } + + invalidTargetAllocation := validIndex() + invalidTargetAllocation.AcceptedAssets = []AcceptedAsset{ + validAcceptedAsset("USDT"), + validAcceptedAsset("USDC"), + } + + duplicatedAcceptedAsset := validIndex() + duplicate := validAcceptedAsset("USDT") + duplicate.TargetAllocation = sdk.MustNewDecFromStr("0.5") + duplicatedAcceptedAsset.AcceptedAssets = []AcceptedAsset{ + duplicate, + duplicate, + } + + tcs := []struct { + name string + i Index + errMsg string + }{ + {"valid index", validIndex(), ""}, + { + "invalid max supply", + invalidMaxSupply, + "maxSupply cannot be negative", + }, + { + "invalid fee", + invalidFee, + "should be between 0.0 and 1.0", + }, + { + "invalid denom accepted asset", + invalidDenomAcceptedAsset, + "invalid denom", + }, + { + "invalid accepted asset", + invalidAcceptedAsset, + "should be between 0.0 and 1.0", + }, + { + "invalid total allocation", + invalidTargetAllocation, + "of all the accepted assets should be 1.0", + }, + { + "duplicated accepted asset", + duplicatedAcceptedAsset, + "duplicated accepted asset", + }, + } + + for _, tc := range tcs { + t.Run( + tc.name, func(t *testing.T) { + err := tc.i.Validate() + if tc.errMsg != "" { + assert.ErrorContains(t, err, tc.errMsg) + } else { + assert.NilError(t, err) + } + }, + ) + } +} + +func TestFee_Validate(t *testing.T) { + invalidMinFee := validFee() + invalidMinFee.MinFee = sdk.MustNewDecFromStr("1.01") + + negativeBalancedFee := validFee() + negativeBalancedFee.BalancedFee = sdk.MustNewDecFromStr("-1.01") + + greaterOneBalancedFee := validFee() + greaterOneBalancedFee.BalancedFee = sdk.MustNewDecFromStr("1.01") + + balancedFeeLowerMinFee := validFee() + balancedFeeLowerMinFee.BalancedFee = sdk.MustNewDecFromStr("0.0001") + + negativeMaxFee := validFee() + negativeMaxFee.MaxFee = sdk.MustNewDecFromStr("-1.01") + + greaterOneMaxFee := validFee() + greaterOneMaxFee.MaxFee = sdk.MustNewDecFromStr("1.01") + + maxFeeEqualBalancedFee := validFee() + maxFeeEqualBalancedFee.MaxFee = sdk.MustNewDecFromStr("0.2") + + tcs := []struct { + name string + f Fee + errMsg string + }{ + {"valid fee", validFee(), ""}, + { + "min_fee > 1.0", + invalidMinFee, + "should be between 0.0 and 1.0", + }, + { + "negative balanced_fee", + negativeBalancedFee, + "should be between 0.0 and 1.0", + }, + { + "balanced_fee > 1.0", + greaterOneBalancedFee, + "should be between 0.0 and 1.0", + }, + { + "balanced_fee lower min_fee", + balancedFeeLowerMinFee, + "should be greater than min_fee", + }, + { + "negative max_fee", + negativeMaxFee, + "should be between 0.0 and 1.0", + }, + { + "max_fee > 1.0", + greaterOneMaxFee, + "should be between 0.0 and 1.0", + }, + { + "max_fee = balanced_fee", + maxFeeEqualBalancedFee, + "should be greater than balanced_fee", + }, + } + + for _, tc := range tcs { + t.Run( + tc.name, func(t *testing.T) { + err := tc.f.Validate() + if tc.errMsg != "" { + assert.ErrorContains(t, err, tc.errMsg) + } else { + assert.NilError(t, err) + } + }, + ) + } +} + +func TestAcceptedAsset_Validate(t *testing.T) { + invalidTargetAllocation := validAcceptedAsset("USDT") + invalidTargetAllocation.TargetAllocation = sdk.MustNewDecFromStr("1.1") + + tcs := []struct { + name string + aa AcceptedAsset + errMsg string + }{ + {"valid accepted asset", validAcceptedAsset("USDT"), ""}, + { + "invalid target allocation", + invalidTargetAllocation, + "should be between 0.0 and 1.0", + }, + } + + for _, tc := range tcs { + t.Run( + tc.name, func(t *testing.T) { + err := tc.aa.Validate() + if tc.errMsg != "" { + assert.ErrorContains(t, err, tc.errMsg) + } else { + assert.NilError(t, err) + } + }, + ) + } +} + +func validIndex() Index { + return Index{ + Denom: "me/USD", + MaxSupply: sdkmath.ZeroInt(), + Exponent: 6, + Fee: validFee(), + AcceptedAssets: []AcceptedAsset{ + validAcceptedAsset("USDT"), + }, + } +} + +func validFee() Fee { + return NewFee( + sdk.MustNewDecFromStr("0.001"), + sdk.MustNewDecFromStr("0.2"), + sdk.MustNewDecFromStr("0.5"), + ) +} + +func validAcceptedAsset(denom string) AcceptedAsset { + return NewAcceptedAsset( + denom, + sdk.MustNewDecFromStr("0.2"), + sdk.MustNewDecFromStr("1.0"), + ) +} diff --git a/x/metoken/keeper/balance.go b/x/metoken/keeper/balance.go new file mode 100644 index 0000000000..c5ba9f91d3 --- /dev/null +++ b/x/metoken/keeper/balance.go @@ -0,0 +1,32 @@ +package keeper + +import ( + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/umee-network/umee/v5/util/store" + "github.com/umee-network/umee/v5/x/metoken" +) + +// IndexBalances returns Index Token supply, if it's not found returns an error. +func (k Keeper) IndexBalances(meTokenDenom string) (metoken.IndexBalances, error) { + balance := store.GetValue[*metoken.IndexBalances](k.store, keyBalance(meTokenDenom), "balance") + if balance == nil { + return metoken.IndexBalances{}, sdkerrors.ErrNotFound.Wrapf("balance for index %s not found", meTokenDenom) + } + + return *balance, nil +} + +// setIndexBalances saves an Index's Balance +func (k Keeper) setIndexBalances(balance metoken.IndexBalances) error { + if err := balance.Validate(); err != nil { + return err + } + + return store.SetValue(k.store, keyBalance(balance.MetokenSupply.Denom), &balance, "balance") +} + +// hasIndexBalance returns true when Index exists. +func (k Keeper) hasIndexBalance(meTokenDenom string) bool { + balance := store.GetValue[*metoken.IndexBalances](k.store, keyBalance(meTokenDenom), "balance") + return balance != nil +} diff --git a/x/metoken/keeper/balance_test.go b/x/metoken/keeper/balance_test.go new file mode 100644 index 0000000000..0a76971848 --- /dev/null +++ b/x/metoken/keeper/balance_test.go @@ -0,0 +1,24 @@ +package keeper + +import ( + "testing" + + "github.com/umee-network/umee/v5/x/metoken/mocks" + + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/stretchr/testify/require" +) + +func TestUnitBalance(t *testing.T) { + k := initSimpleKeeper(t) + + _, err := k.IndexBalances("inexistingMetoken") + require.ErrorIs(t, err, sdkerrors.ErrNotFound) + + balance := mocks.ValidUSDIndexBalances(mocks.MeUSDDenom) + err = k.setIndexBalances(balance) + + balance2, err := k.IndexBalances(balance.MetokenSupply.Denom) + require.NoError(t, err) + require.Equal(t, balance, balance2) +} diff --git a/x/metoken/keeper/fee.go b/x/metoken/keeper/fee.go new file mode 100644 index 0000000000..ab6f130c3c --- /dev/null +++ b/x/metoken/keeper/fee.go @@ -0,0 +1,133 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/umee-network/umee/v5/x/metoken" +) + +// swapFee to be charged to the user, given a specific Index configuration and asset amount. +func (k Keeper) swapFee(index metoken.Index, indexPrices metoken.IndexPrices, asset sdk.Coin) ( + sdk.Coin, + error, +) { + i, assetSettings := index.AcceptedAsset(asset.Denom) + if i < 0 { + return sdk.Coin{}, sdkerrors.ErrNotFound.Wrapf("asset %s is not accepted in the index", asset.Denom) + } + + // charge max fee if we don't want the token in the index. + if assetSettings.TargetAllocation.IsZero() { + return sdk.NewCoin(asset.Denom, index.Fee.MaxFee.MulInt(asset.Amount).TruncateInt()), nil + } + + currentAllocation, err := k.currentAllocation(index, indexPrices, asset.Denom) + if err != nil { + return sdk.Coin{}, err + } + + // when current_allocation is zero, we incentivize the swap by charging only min_fee + if currentAllocation.IsZero() { + return sdk.NewCoin(asset.Denom, index.Fee.MinFee.MulInt(asset.Amount).TruncateInt()), nil + } + + allocationDeviation := currentAllocation.Sub(assetSettings.TargetAllocation).Quo(assetSettings.TargetAllocation) + fee := index.Fee.CalculateFee(allocationDeviation) + return sdk.NewCoin(asset.Denom, fee.MulInt(asset.Amount).TruncateInt()), nil +} + +// redeemFee to be charged to the user, given a specific Index configuration and asset amount. +func (k Keeper) redeemFee(index metoken.Index, indexPrices metoken.IndexPrices, asset sdk.Coin) ( + sdk.Coin, + error, +) { + i, assetSettings := index.AcceptedAsset(asset.Denom) + if i < 0 { + return sdk.Coin{}, sdkerrors.ErrNotFound.Wrapf("asset %s is not accepted in the index", asset.Denom) + } + + // charge min fee if we don't want the token in the index. + if assetSettings.TargetAllocation.IsZero() { + return sdk.NewCoin(asset.Denom, index.Fee.MinFee.MulInt(asset.Amount).TruncateInt()), nil + } + + allocationDeviation, err := k.redeemAllocationDeviation( + index, + indexPrices, + asset.Denom, + assetSettings.TargetAllocation, + ) + if err != nil { + return sdk.Coin{}, err + } + + fee := index.Fee.CalculateFee(allocationDeviation) + return sdk.NewCoin(asset.Denom, fee.MulInt(asset.Amount).TruncateInt()), nil +} + +// currentAllocation returns a factor of the assetDenom supply in the index based on the USD price value. +func (k Keeper) currentAllocation( + index metoken.Index, + indexPrices metoken.IndexPrices, + assetDenom string, +) (sdk.Dec, error) { + balances, err := k.IndexBalances(index.Denom) + if err != nil { + return sdk.Dec{}, err + } + + i, balance := balances.AssetBalance(assetDenom) + if i < 0 { + return sdk.Dec{}, sdkerrors.ErrNotFound.Wrapf("balance for denom %s not found", assetDenom) + } + + // if asset wasn't supplied to the index yet, the allocation is zero + if balance.AvailableSupply().IsZero() { + return sdk.ZeroDec(), nil + } + + // if no meToken in balance, the allocation is zero + if !balances.MetokenSupply.IsPositive() { + return sdk.ZeroDec(), nil + } + + assetPrice, err := indexPrices.Price(assetDenom) + if err != nil { + return sdk.Dec{}, err + } + assetUSD, err := valueInUSD(balance.AvailableSupply(), assetPrice.Price, assetPrice.Exponent) + if err != nil { + return sdk.Dec{}, err + } + + meTokenPrice, err := indexPrices.Price(index.Denom) + if err != nil { + return sdk.Dec{}, err + } + meTokenUSD, err := valueInUSD(balances.MetokenSupply.Amount, meTokenPrice.Price, meTokenPrice.Exponent) + if err != nil { + return sdk.Dec{}, err + } + + return assetUSD.Quo(meTokenUSD), nil +} + +// redeemAllocationDeviation returns the delta between the target allocation and current allocation of an asset in an +// index for a redemption. It returns negative value when the asset is oversupplied. +func (k Keeper) redeemAllocationDeviation( + index metoken.Index, + indexPrices metoken.IndexPrices, + assetDenom string, + targetAllocation sdk.Dec, +) (sdk.Dec, error) { + currentAllocation, err := k.currentAllocation(index, indexPrices, assetDenom) + if err != nil { + return sdk.Dec{}, err + } + + if currentAllocation.IsZero() { + return targetAllocation, nil + } + + return targetAllocation.Sub(currentAllocation).Quo(targetAllocation), nil +} diff --git a/x/metoken/keeper/fee_test.go b/x/metoken/keeper/fee_test.go new file mode 100644 index 0000000000..c14d1b1ec7 --- /dev/null +++ b/x/metoken/keeper/fee_test.go @@ -0,0 +1,89 @@ +package keeper + +import ( + "testing" + + "github.com/stretchr/testify/require" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + "github.com/umee-network/umee/v5/x/metoken/mocks" +) + +func TestSwapFee(t *testing.T) { + k := initMeUSDKeeper(t, nil, nil, nil) + + index, err := k.RegisteredIndex(mocks.MeUSDDenom) + require.NoError(t, err) + + balance, err := k.IndexBalances(mocks.MeUSDDenom) + require.NoError(t, err) + prices := meUSDIndexPricesAdjustedToBalance(t, balance) + + _, err = k.swapFee(index, prices, sdk.NewCoin("inexistingAsset", sdkmath.ZeroInt())) + require.ErrorIs(t, err, sdkerrors.ErrNotFound) + + // target_allocation = 0 -> fee = max_fee * coin_amount + // fee = 0.5 * 10 = 5 + i, usdtAsset := index.AcceptedAsset(mocks.USDTBaseDenom) + require.True(t, i >= 0) + + usdtAsset.TargetAllocation = sdk.ZeroDec() + index.SetAcceptedAsset(usdtAsset) + tenUSDT := sdk.NewCoin(mocks.USDTBaseDenom, sdkmath.NewInt(10_000000)) + + fee, err := k.swapFee(index, prices, tenUSDT) + require.NoError(t, err) + require.True(t, fee.Amount.Equal(sdkmath.NewInt(5_000000))) + + // swap_fee = balanced_fee + delta_allocation * balanced_fee + // swap_fee = 0.2 + (-0.276727736549164797) * 0.2 = 0.144654452690167041 + // fee = swap_fee * coin_amount + // fee = 0.144654452690167041 * 10 = 1.44654452690167041 + usdtAsset.TargetAllocation = sdk.MustNewDecFromStr("0.33") + index.SetAcceptedAsset(usdtAsset) + + fee, err = k.swapFee(index, prices, tenUSDT) + require.NoError(t, err) + require.True(t, fee.Amount.Equal(sdkmath.NewInt(1_446544))) +} + +func TestRedeemFee(t *testing.T) { + k := initMeUSDKeeper(t, nil, nil, nil) + + index, err := k.RegisteredIndex(mocks.MeUSDDenom) + require.NoError(t, err) + + balance, err := k.IndexBalances(mocks.MeUSDDenom) + require.NoError(t, err) + prices := meUSDIndexPricesAdjustedToBalance(t, balance) + + _, err = k.redeemFee(index, prices, sdk.NewCoin("inexistingAsset", sdkmath.ZeroInt())) + require.ErrorIs(t, err, sdkerrors.ErrNotFound) + + // target_allocation = 0 -> fee = min_fee * coin_amount + // fee = 0.01 * 10 = 0.1 + i, usdtAsset := index.AcceptedAsset(mocks.USDTBaseDenom) + require.True(t, i >= 0) + + usdtAsset.TargetAllocation = sdk.ZeroDec() + index.SetAcceptedAsset(usdtAsset) + tenUSDT := sdk.NewCoin(mocks.USDTBaseDenom, sdkmath.NewInt(10_000000)) + + fee, err := k.redeemFee(index, prices, tenUSDT) + require.NoError(t, err) + require.True(t, fee.Amount.Equal(sdkmath.NewInt(100000))) + + // redeem_fee = balanced_fee + delta_allocation * balanced_fee + // redeem_fee = 0.2 + (0.276727736549164797) * 0.2 = 0.255345547309832959 + // fee = redeem_fee * coin_amount + // fee = 0.255345547309832959 * 10 = 2.55345547309832959 + usdtAsset.TargetAllocation = sdk.MustNewDecFromStr("0.33") + index.SetAcceptedAsset(usdtAsset) + + fee, err = k.redeemFee(index, prices, tenUSDT) + require.NoError(t, err) + require.True(t, fee.Amount.Equal(sdkmath.NewInt(2_553455))) +} diff --git a/x/metoken/keeper/genesis.go b/x/metoken/keeper/genesis.go new file mode 100644 index 0000000000..2cf9dad276 --- /dev/null +++ b/x/metoken/keeper/genesis.go @@ -0,0 +1,39 @@ +package keeper + +import ( + "github.com/umee-network/umee/v5/util" + "github.com/umee-network/umee/v5/x/metoken" +) + +// InitGenesis initializes the x/metoken module's state from a provided genesis state. +func (k Keeper) InitGenesis(genState metoken.GenesisState) { + util.Panic(k.SetParams(genState.Params)) + + for _, index := range genState.Registry { + util.Panic(k.setRegisteredIndex(index)) + } + + for _, balance := range genState.Balances { + util.Panic(k.setIndexBalances(balance)) + } + + k.setNextRebalancingTime(genState.NextRebalancingTime) + k.setNextInterestClaimTime(genState.NextInterestClaimTime) +} + +// ExportGenesis returns the x/metoken module's exported genesis state. +func (k Keeper) ExportGenesis() *metoken.GenesisState { + nextRebalancingTime, err := k.getNextRebalancingTime() + util.Panic(err) + + nextInterestClaimTime, err := k.getNextInterestClaimTime() + util.Panic(err) + + return &metoken.GenesisState{ + Params: k.GetParams(), + Registry: k.GetAllRegisteredIndexes(), + Balances: k.GetAllIndexesBalances(), + NextRebalancingTime: nextRebalancingTime, + NextInterestClaimTime: nextInterestClaimTime, + } +} diff --git a/x/metoken/keeper/genesis_test.go b/x/metoken/keeper/genesis_test.go new file mode 100644 index 0000000000..bc07386eac --- /dev/null +++ b/x/metoken/keeper/genesis_test.go @@ -0,0 +1,113 @@ +package keeper + +import ( + "testing" + "time" + + "github.com/umee-network/umee/v5/x/metoken/mocks" + + "github.com/umee-network/umee/v5/util/coin" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/assert" + "github.com/umee-network/umee/v5/x/metoken" +) + +func TestKeeper_InitGenesis(t *testing.T) { + keeper := initSimpleKeeper(t) + + invalidRegistry := *metoken.DefaultGenesisState() + invalidRegistry.Registry = []metoken.Index{ + metoken.NewIndex("token", sdkmath.ZeroInt(), 6, metoken.Fee{}, nil), + } + + invalidBalance := *metoken.DefaultGenesisState() + invalidBalance.Balances = []metoken.IndexBalances{ + { + MetokenSupply: sdk.Coin{ + Denom: "test", + Amount: sdkmath.ZeroInt(), + }, + AssetBalances: nil, + }, + } + + tcs := []struct { + name string + g metoken.GenesisState + errMsg string + }{ + {"valid genesis", *metoken.DefaultGenesisState(), ""}, + { + "invalid registry", + invalidRegistry, + "meToken denom token should have the following format: me/: invalid request", + }, + { + "invalid balances", + invalidBalance, + "meToken denom test should have the following format: me/: invalid request", + }, + } + + for _, tc := range tcs { + t.Run( + tc.name, func(t *testing.T) { + if tc.errMsg != "" { + assert.PanicsWithError(t, tc.errMsg, func() { keeper.InitGenesis(tc.g) }) + } else { + assert.NotPanics(t, func() { keeper.InitGenesis(tc.g) }) + } + }, + ) + } +} + +func TestKeeper_ExportGenesis(t *testing.T) { + keeper := initSimpleKeeper(t) + + usdt := "USDT" + int0 := sdkmath.ZeroInt() + expectedGenesis := *metoken.DefaultGenesisState() + expectedGenesis.Registry = []metoken.Index{ + { + Denom: mocks.MeUSDDenom, + MaxSupply: sdkmath.ZeroInt(), + Fee: metoken.NewFee( + sdk.MustNewDecFromStr("0.001"), + sdk.MustNewDecFromStr("0.2"), + sdk.MustNewDecFromStr("0.5"), + ), + AcceptedAssets: []metoken.AcceptedAsset{ + metoken.NewAcceptedAsset( + usdt, + sdk.MustNewDecFromStr("0.2"), + sdk.MustNewDecFromStr("1.0"), + ), + }, + }, + } + expectedGenesis.Balances = []metoken.IndexBalances{ + { + MetokenSupply: coin.Zero(mocks.MeUSDDenom), + AssetBalances: []metoken.AssetBalance{ + metoken.NewAssetBalance( + usdt, + int0, + int0, + int0, + int0, + ), + }, + }, + } + expectedGenesis.NextRebalancingTime = time.UnixMilli(time.Now().UnixMilli()) + expectedGenesis.NextInterestClaimTime = time.UnixMilli(time.Now().UnixMilli()) + + assert.NotPanics(t, func() { keeper.InitGenesis(expectedGenesis) }) + + resultGenesis := keeper.ExportGenesis() + + assert.Equal(t, expectedGenesis, *resultGenesis) +} diff --git a/x/metoken/keeper/grpc_query.go b/x/metoken/keeper/grpc_query.go new file mode 100644 index 0000000000..a7f7aa5438 --- /dev/null +++ b/x/metoken/keeper/grpc_query.go @@ -0,0 +1,143 @@ +package keeper + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/umee-network/umee/v5/x/metoken" +) + +var _ metoken.QueryServer = Querier{} + +// Querier implements a QueryServer for the x/metoken module. +type Querier struct { + Builder +} + +// Params returns params of the x/metoken module. +func (q Querier) Params(goCtx context.Context, _ *metoken.QueryParams) (*metoken.QueryParamsResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + params := q.Keeper(&ctx).GetParams() + + return &metoken.QueryParamsResponse{Params: params}, nil +} + +// Indexes returns registered indexes in the x/metoken module. If index denom is not specified, +// returns all the registered indexes. +func (q Querier) Indexes(goCtx context.Context, req *metoken.QueryIndexes) (*metoken.QueryIndexesResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + k := q.Keeper(&ctx) + + var indexes []metoken.Index + if len(req.MetokenDenom) == 0 { + indexes = k.GetAllRegisteredIndexes() + } else { + index, err := k.RegisteredIndex(req.MetokenDenom) + if err != nil { + return nil, err + } + indexes = []metoken.Index{index} + } + + return &metoken.QueryIndexesResponse{ + Registry: indexes, + }, nil +} + +// SwapFee returns the fee for the swap operation, given a specific amount of tokens and the meToken denom. +func (q Querier) SwapFee(goCtx context.Context, req *metoken.QuerySwapFee) (*metoken.QuerySwapFeeResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + k := q.Keeper(&ctx) + + if err := req.Asset.Validate(); err != nil { + return nil, err + } + + index, err := k.RegisteredIndex(req.MetokenDenom) + if err != nil { + return nil, err + } + + // get index prices + indexPrices, err := k.Prices(index) + if err != nil { + return nil, err + } + + // calculate the fee for the asset amount + swapFee, err := k.swapFee(index, indexPrices, req.Asset) + if err != nil { + return nil, err + } + + return &metoken.QuerySwapFeeResponse{Asset: swapFee}, nil +} + +// RedeemFee returns the fee for the redeem operation, given a specific amount of meTokens and the asset denom. +func (q Querier) RedeemFee(goCtx context.Context, req *metoken.QueryRedeemFee) ( + *metoken.QueryRedeemFeeResponse, + error, +) { + ctx := sdk.UnwrapSDKContext(goCtx) + k := q.Keeper(&ctx) + + if err := req.Metoken.Validate(); err != nil { + return nil, err + } + + index, err := k.RegisteredIndex(req.Metoken.Denom) + if err != nil { + return nil, err + } + + // get index prices + indexPrices, err := k.Prices(index) + if err != nil { + return nil, err + } + + // calculate amount to withdraw from x/metoken and x/leverage + amountFromReserves, amountFromLeverage, err := k.calculateRedeem(index, indexPrices, req.Metoken, req.AssetDenom) + if err != nil { + return nil, err + } + + // calculate the fee for the asset amount that would be given for a redemption + toRedeem := sdk.NewCoin(req.AssetDenom, amountFromReserves.Add(amountFromLeverage)) + redeemFee, err := k.redeemFee(index, indexPrices, toRedeem) + if err != nil { + return nil, err + } + + return &metoken.QueryRedeemFeeResponse{Asset: redeemFee}, nil +} + +// IndexBalances returns balances from the x/metoken module. If index balance denom is not specified, +// returns all the balances. +func (q Querier) IndexBalances( + goCtx context.Context, + req *metoken.QueryIndexBalances, +) (*metoken.QueryIndexBalancesResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + k := q.Keeper(&ctx) + + var balances []metoken.IndexBalances + if len(req.MetokenDenom) == 0 { + balances = k.GetAllIndexesBalances() + } else { + balance, err := k.IndexBalances(req.MetokenDenom) + if err != nil { + return nil, err + } + balances = []metoken.IndexBalances{balance} + } + + return &metoken.QueryIndexBalancesResponse{ + IndexBalances: balances, + }, nil +} + +// NewQuerier returns Querier object. +func NewQuerier(kb Builder) Querier { + return Querier{Builder: kb} +} diff --git a/x/metoken/keeper/intest/grpc_query_test.go b/x/metoken/keeper/intest/grpc_query_test.go new file mode 100644 index 0000000000..d2e3a970ad --- /dev/null +++ b/x/metoken/keeper/intest/grpc_query_test.go @@ -0,0 +1,282 @@ +package keeper_test + +import ( + "testing" + + "github.com/umee-network/umee/v5/x/metoken/mocks" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/umee-network/umee/v5/x/metoken" + "gotest.tools/v3/assert" +) + +func TestQuerier_Params(t *testing.T) { + s := initKeeperTestSuite(t, nil, nil) + querier, ctx := s.queryClient, s.ctx + + resp, err := querier.Params(ctx, nil) + assert.NilError(t, err) + assert.Check(t, resp.Params.RebalancingFrequency > 0) + assert.Check(t, resp.Params.ClaimingFrequency > 0) +} + +func TestQuerier_Indexes(t *testing.T) { + index1 := mocks.StableIndex(mocks.MeUSDDenom) + index2 := mocks.StableIndex("me/EUR") + + s := initKeeperTestSuite(t, []metoken.Index{index1, index2}, nil) + querier, ctx := s.queryClient, s.ctx + + tcs := []struct { + name string + denom string + expIndexCount int + expErr string + }{ + { + "get all indexes", + "", + 2, + "", + }, + { + "get index found", + mocks.MeUSDDenom, + 1, + "", + }, + { + "get index not found", + "me/Test", + 0, + "not found", + }, + } + + for _, tc := range tcs { + t.Run( + tc.name, func(t *testing.T) { + resp, err := querier.Indexes( + ctx, &metoken.QueryIndexes{ + MetokenDenom: tc.denom, + }, + ) + if len(tc.expErr) == 0 { + assert.NilError(t, err) + assert.Check(t, tc.expIndexCount == len(resp.Registry)) + } else { + assert.ErrorContains(t, err, tc.expErr) + } + }, + ) + } +} + +func TestQuerier_Balances(t *testing.T) { + balance1 := mocks.ValidUSDIndexBalances(mocks.MeUSDDenom) + balance2 := mocks.ValidUSDIndexBalances("me/EUR") + + s := initKeeperTestSuite(t, nil, []metoken.IndexBalances{balance1, balance2}) + querier, ctx := s.queryClient, s.ctx + + tcs := []struct { + name string + denom string + expIndexCount int + expErr string + }{ + { + "get all balances", + "", + 2, + "", + }, + { + "get balance found", + mocks.MeUSDDenom, + 1, + "", + }, + { + "get balance not found", + "me/Test", + 0, + "not found", + }, + } + + for _, tc := range tcs { + t.Run( + tc.name, func(t *testing.T) { + resp, err := querier.IndexBalances( + ctx, &metoken.QueryIndexBalances{ + MetokenDenom: tc.denom, + }, + ) + if len(tc.expErr) > 0 { + assert.ErrorContains(t, err, tc.expErr) + } else { + assert.NilError(t, err) + assert.Check(t, tc.expIndexCount == len(resp.IndexBalances)) + } + }, + ) + } +} + +type feeTestCase struct { + name string + asset sdk.Coin + denom string +} + +func TestQuerier_SwapFee_meUSD(t *testing.T) { + index := mocks.StableIndex(mocks.MeUSDDenom) + balances := mocks.ValidUSDIndexBalances(mocks.MeUSDDenom) + + s := initKeeperTestSuite(t, []metoken.Index{index}, []metoken.IndexBalances{balances}) + querier, ctx := s.queryClient, s.ctx + + // set prices + prices := metoken.NewIndexPrices() + prices.SetPrice(mocks.USDTBaseDenom, mocks.USDTPrice, 6) + prices.SetPrice(mocks.USDCBaseDenom, mocks.USDCPrice, 6) + prices.SetPrice(mocks.ISTBaseDenom, mocks.ISTPrice, 6) + + totalValue := sdk.ZeroDec() + values := make(map[string]sdk.Dec) + for _, balance := range balances.AssetBalances { + // calculate total asset supply (leveraged + reserved) + assetSupply := balance.AvailableSupply() + // get asset Price + assetPrice, err := prices.Price(balance.Denom) + assert.NilError(t, err) + // calculate asset value + assetValue := assetPrice.Price.MulInt(assetSupply) + + // add asset value to the totalValue + totalValue = totalValue.Add(assetValue) + // calculate every asset balance value + values[balance.Denom] = assetValue + } + + tcs := []feeTestCase{ + { + name: "10 USDT swap", + asset: sdk.NewCoin(mocks.USDTBaseDenom, sdkmath.NewInt(10_000000)), + denom: mocks.MeUSDDenom, + }, + { + name: "750 USDC swap", + asset: sdk.NewCoin(mocks.USDCBaseDenom, sdkmath.NewInt(750_000000)), + denom: mocks.MeUSDDenom, + }, + { + name: "1876 IST swap", + asset: sdk.NewCoin(mocks.ISTBaseDenom, sdkmath.NewInt(1876_000000)), + denom: mocks.MeUSDDenom, + }, + } + + for _, tc := range tcs { + req := &metoken.QuerySwapFee{ + Asset: tc.asset, + MetokenDenom: tc.denom, + } + denom := tc.asset.Denom + + resp, err := querier.SwapFee(ctx, req) + assert.NilError(t, err) + + // current_allocation = asset_value / total_value + currentAllocation := values[denom].Quo(totalValue) + i, aa := index.AcceptedAsset(denom) + assert.Check(t, i >= 0) + targetAllocation := aa.TargetAllocation + + // swap_delta_allocation = (current_allocation - target_allocation) / target_allocation + swapDeltaAllocation := currentAllocation.Sub(targetAllocation).Quo(targetAllocation) + + // fee = delta_allocation * balanced_fee + balanced_fee + fee := swapDeltaAllocation.Mul(index.Fee.BalancedFee).Add(index.Fee.BalancedFee) + + // swap_fee = fee * amount + result := fee.MulInt(tc.asset.Amount).TruncateInt() + + assert.Check(t, result.Equal(resp.Asset.Amount)) + } +} + +func TestQuerier_RedeemFee_meUSD(t *testing.T) { + index := mocks.StableIndex(mocks.MeUSDDenom) + balances := mocks.ValidUSDIndexBalances(mocks.MeUSDDenom) + + s := initKeeperTestSuite(t, []metoken.Index{index}, []metoken.IndexBalances{balances}) + querier, ctx, app := s.queryClient, s.ctx, s.app + + // set prices + prices, err := app.MetokenKeeperB.Keeper(&ctx).Prices(index) + assert.NilError(t, err) + + tcs := []feeTestCase{ + { + name: "20 meUSD to USDT redemption", + asset: sdk.NewCoin(mocks.MeUSDDenom, sdkmath.NewInt(20_000000)), + denom: mocks.USDTBaseDenom, + }, + { + name: "444 meUSD to USDC redemption", + asset: sdk.NewCoin(mocks.MeUSDDenom, sdkmath.NewInt(444_000000)), + denom: mocks.USDCBaseDenom, + }, + { + name: "1267 meUSD to IST redemption", + asset: sdk.NewCoin(mocks.MeUSDDenom, sdkmath.NewInt(1267_000000)), + denom: mocks.ISTBaseDenom, + }, + } + + for _, tc := range tcs { + req := &metoken.QueryRedeemFee{ + Metoken: tc.asset, + AssetDenom: tc.denom, + } + meTokenDenom, denom := tc.asset.Denom, tc.denom + + resp, err := querier.RedeemFee(ctx, req) + assert.NilError(t, err) + + price, err := prices.Price(denom) + assert.NilError(t, err) + i, balance := balances.AssetBalance(denom) + assert.Check(t, i >= 0) + supply := balance.AvailableSupply() + + meTokenPrice, err := prices.Price(meTokenDenom) + assert.NilError(t, err) + + // current_allocation = asset_value / total_value + currentAllocation := price.Price.MulInt(supply).Quo(meTokenPrice.Price.MulInt(balances.MetokenSupply.Amount)) + i, aa := index.AcceptedAsset(denom) + assert.Check(t, i >= 0) + targetAllocation := aa.TargetAllocation + + // redeem_delta_allocation = (target_allocation - current_allocation) / target_allocation + redeemDeltaAllocation := targetAllocation.Sub(currentAllocation).Quo(targetAllocation) + + // fee = delta_allocation * balanced_fee + balanced_fee + fee := redeemDeltaAllocation.Mul(index.Fee.BalancedFee).Add(index.Fee.BalancedFee) + + // exchange_rate = metoken_price / asset_price + exchangeRate := meTokenPrice.Price.Quo(price.Price) + + // asset_to_redeem = exchange_rate * asset_amount + toRedeem := exchangeRate.MulInt(tc.asset.Amount).TruncateInt() + + // total_fee = asset_to_redeem * fee + totalFee := fee.MulInt(toRedeem).TruncateInt() + + assert.Check(t, totalFee.Equal(resp.Asset.Amount)) + } +} diff --git a/x/metoken/keeper/intest/keeper_test.go b/x/metoken/keeper/intest/keeper_test.go new file mode 100644 index 0000000000..265d9d6770 --- /dev/null +++ b/x/metoken/keeper/intest/keeper_test.go @@ -0,0 +1,138 @@ +package keeper_test + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/baseapp" + sdkmath "cosmossdk.io/math" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + tmrand "github.com/tendermint/tendermint/libs/rand" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + + umeeapp "github.com/umee-network/umee/v5/app" + "github.com/umee-network/umee/v5/x/metoken" + "github.com/umee-network/umee/v5/x/metoken/keeper" + "github.com/umee-network/umee/v5/x/metoken/mocks" +) + +type KeeperTestSuite struct { + ctx sdk.Context + app *umeeapp.UmeeApp + queryClient metoken.QueryClient + msgServer metoken.MsgServer + + setupAccountCounter sdkmath.Int + addrs []sdk.AccAddress +} + +// initKeeperTestSuite creates a full keeper with all the external dependencies mocked +func initKeeperTestSuite(t *testing.T, registry []metoken.Index, balances []metoken.IndexBalances) *KeeperTestSuite { + t.Parallel() + isCheckTx := false + app := umeeapp.Setup(t) + ctx := app.NewContext( + isCheckTx, tmproto.Header{ + ChainID: fmt.Sprintf("test-chain-%s", tmrand.Str(4)), + Height: 9, + }, + ) + + oracleMock := mocks.NewMockOracleKeeper() + oracleMock.AllMedianPricesFunc.SetDefaultHook(mocks.ValidPricesFunc()) + + kb := keeper.NewKeeperBuilder( + app.AppCodec(), + app.GetKey(metoken.ModuleName), + app.BankKeeper, + app.LeverageKeeper, + oracleMock, + ) + app.MetokenKeeperB = kb + + genState := metoken.DefaultGenesisState() + genState.Registry = registry + genState.Balances = balances + kb.Keeper(&ctx).InitGenesis(*genState) + + queryHelper := baseapp.NewQueryServerTestHelper(ctx, app.InterfaceRegistry()) + metoken.RegisterQueryServer(queryHelper, keeper.NewQuerier(app.MetokenKeeperB)) + + require.NoError( + t, + app.LeverageKeeper.SetTokenSettings( + ctx, + mocks.ValidToken(mocks.USDTBaseDenom, mocks.USDTSymbolDenom, 6), + ), + ) + require.NoError( + t, + app.LeverageKeeper.SetTokenSettings( + ctx, + mocks.ValidToken(mocks.USDCBaseDenom, mocks.USDCSymbolDenom, 6), + ), + ) + require.NoError( + t, + app.LeverageKeeper.SetTokenSettings( + ctx, + mocks.ValidToken(mocks.ISTBaseDenom, mocks.ISTSymbolDenom, 6), + ), + ) + require.NoError( + t, + app.LeverageKeeper.SetTokenSettings( + ctx, + mocks.ValidToken(mocks.WBTCBaseDenom, mocks.WBTCSymbolDenom, 8), + ), + ) + require.NoError( + t, + app.LeverageKeeper.SetTokenSettings( + ctx, + mocks.ValidToken(mocks.ETHBaseDenom, mocks.ETHSymbolDenom, 18), + ), + ) + + return &KeeperTestSuite{ + ctx: ctx, + app: app, + queryClient: metoken.NewQueryClient(queryHelper), + msgServer: keeper.NewMsgServerImpl(app.MetokenKeeperB), + setupAccountCounter: sdkmath.ZeroInt(), + addrs: umeeapp.AddTestAddrsIncremental(app, ctx, 1, sdk.NewInt(3000000)), + } +} + +// newAccount creates a new account for testing, and funds it with any input tokens. +func (s *KeeperTestSuite) newAccount(t *testing.T, funds ...sdk.Coin) sdk.AccAddress { + app, ctx := s.app, s.ctx + + // create a unique address + s.setupAccountCounter = s.setupAccountCounter.Add(sdk.OneInt()) + addrStr := fmt.Sprintf("%-20s", "addr"+s.setupAccountCounter.String()+"_______________") + addr := sdk.AccAddress([]byte(addrStr)) + + // register the account in AccountKeeper + acct := app.AccountKeeper.NewAccountWithAddress(ctx, addr) + app.AccountKeeper.SetAccount(ctx, acct) + + s.fundAccount(t, addr, funds...) + + return addr +} + +// fundAccount mints and sends tokens to an account for testing. +func (s *KeeperTestSuite) fundAccount(t *testing.T, addr sdk.AccAddress, funds ...sdk.Coin) { + app, ctx := s.app, s.ctx + + coins := sdk.NewCoins(funds...) + if !coins.IsZero() { + // mint and send tokens to account + require.NoError(t, app.BankKeeper.MintCoins(ctx, minttypes.ModuleName, coins)) + require.NoError(t, app.BankKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, addr, coins)) + } +} diff --git a/x/metoken/keeper/intest/msg_server_test.go b/x/metoken/keeper/intest/msg_server_test.go new file mode 100644 index 0000000000..590a3b3a9b --- /dev/null +++ b/x/metoken/keeper/intest/msg_server_test.go @@ -0,0 +1,1894 @@ +package keeper_test + +import ( + "testing" + + otypes "github.com/umee-network/umee/v5/x/oracle/types" + + "github.com/umee-network/umee/v5/x/metoken/mocks" + + "github.com/stretchr/testify/require" + "gotest.tools/v3/assert" + + "github.com/umee-network/umee/v5/util/coin" + "github.com/umee-network/umee/v5/x/metoken" + "github.com/umee-network/umee/v5/x/metoken/keeper" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +type testCase struct { + name string + addr sdk.AccAddress + asset sdk.Coin + denom string + errMsg string +} + +func TestMsgServer_Swap(t *testing.T) { + index := mocks.StableIndex(mocks.MeUSDDenom) + + s := initKeeperTestSuite(t, nil, nil) + msgServer, ctx, app := s.msgServer, s.ctx, s.app + + _, err := msgServer.GovUpdateRegistry( + ctx, &metoken.MsgGovUpdateRegistry{ + Authority: app.GovKeeper.GetGovernanceAccount(s.ctx).GetAddress().String(), + AddIndex: []metoken.Index{index}, + UpdateIndex: nil, + }, + ) + require.NoError(t, err) + + // create and fund a user with 100 USDT, 1000 USDC and 2000000 IST + user := s.newAccount( + t, + coin.New(mocks.USDTBaseDenom, 100_000000), + coin.New(mocks.USDCBaseDenom, 1000_000000), + coin.New(mocks.ISTBaseDenom, 2_000_000_000000), + ) + + tcs := []testCase{ + { + "invalid user address", + sdk.AccAddress{}, + sdk.Coin{}, + "", + "empty address string is not allowed", + }, + { + "invalid invalid asset", + user, + sdk.Coin{ + Denom: "???", + Amount: sdkmath.ZeroInt(), + }, + "", + "invalid denom", + }, + { + "invalid meToken denom", + user, + coin.New(mocks.USDTBaseDenom, 100_000000), + "???", + "invalid denom", + }, + { + "valid - swap 73 usdt", + user, + coin.New(mocks.USDTBaseDenom, 73_000000), + mocks.MeUSDDenom, + "", + }, + { + "valid - swap 750 usdc", + user, + coin.New(mocks.USDCBaseDenom, 750_000000), + mocks.MeUSDDenom, + "", + }, + { + "valid - swap 1876 ist", + user, + coin.New(mocks.ISTBaseDenom, 1876_000000), + mocks.MeUSDDenom, + "", + }, + { + "invalid - index not found", + user, + coin.New(mocks.ISTBaseDenom, 100_000000), + "me/EUR", + "index me/EUR not found", + }, + { + "invalid - asset not present en balances", + user, + coin.New(mocks.WBTCBaseDenom, 100_000000), + mocks.MeUSDDenom, + "is not accepted in the index", + }, + { + "max supply reached", + user, + coin.New(mocks.ISTBaseDenom, 1_900_000_000000), + mocks.MeUSDDenom, + "reaching the max supply", + }, + } + + for _, tc := range tcs { + msg := &metoken.MsgSwap{ + User: tc.addr.String(), + Asset: tc.asset, + MetokenDenom: tc.denom, + } + if len(tc.errMsg) > 0 { + _, err := msgServer.Swap(ctx, msg) + assert.ErrorContains(t, err, tc.errMsg, tc.name) + } else { + meTokenDenom := tc.denom + k := app.MetokenKeeperB.Keeper(&ctx) + + // initial state + iUserBalance := app.BankKeeper.GetAllBalances(ctx, tc.addr) + iUTokenSupply := app.LeverageKeeper.GetAllUTokenSupply(ctx) + iMeTokenBalance, err := k.IndexBalances(meTokenDenom) + require.NoError(t, err) + + prices, err := k.Prices(index) + require.NoError(t, err) + + // verify the outputs of swap function + resp, err := msgServer.Swap(ctx, msg) + require.NoError(t, err, tc.name) + + // final state + fUserBalance := app.BankKeeper.GetAllBalances(ctx, tc.addr) + fUTokenSupply := app.LeverageKeeper.GetAllUTokenSupply(ctx) + fMeTokenBalance, err := k.IndexBalances(meTokenDenom) + require.NoError(t, err) + + verifySwap( + t, + tc, + index, + iUserBalance, + fUserBalance, + iUTokenSupply, + fUTokenSupply, + iMeTokenBalance, + fMeTokenBalance, + prices, + *resp, + ) + } + } +} + +func TestMsgServer_Swap_NonStableAssets_DiffExponents(t *testing.T) { + index := mocks.NonStableIndex(mocks.MeNonStableDenom) + + s := initKeeperTestSuite(t, nil, nil) + msgServer, ctx, app := s.msgServer, s.ctx, s.app + + _, err := msgServer.GovUpdateRegistry( + ctx, &metoken.MsgGovUpdateRegistry{ + Authority: app.GovKeeper.GetGovernanceAccount(s.ctx).GetAddress().String(), + AddIndex: []metoken.Index{index}, + UpdateIndex: nil, + }, + ) + require.NoError(t, err) + + // create and fund a user with 10000 USDT, 1.431 WBTC, 2.876 ETH + user := s.newAccount( + t, + coin.New(mocks.USDTBaseDenom, 10000_000000), + coin.New(mocks.WBTCBaseDenom, 1_43100000), + coin.New(mocks.ETHBaseDenom, 2_876000000000000000), + ) + + tcs := []testCase{ + { + "valid - first swap 1547 USDT", + user, + coin.New(mocks.USDTBaseDenom, 1547_000000), + mocks.MeNonStableDenom, + "", + }, + { + "valid - swap 0.57686452 WBTC", + user, + coin.New(mocks.WBTCBaseDenom, 57686452), + mocks.MeNonStableDenom, + "", + }, + { + "valid - swap 1.435125562353141231 ETH", + user, + coin.New(mocks.ETHBaseDenom, 1_435125562353141231), + mocks.MeNonStableDenom, + "", + }, + } + + for _, tc := range tcs { + msg := &metoken.MsgSwap{ + User: tc.addr.String(), + Asset: tc.asset, + MetokenDenom: tc.denom, + } + if len(tc.errMsg) > 0 { + _, err := msgServer.Swap(ctx, msg) + assert.ErrorContains(t, err, tc.errMsg) + } else { + meTokenDenom := tc.denom + k := app.MetokenKeeperB.Keeper(&ctx) + + // initial state + iUserBalance := app.BankKeeper.GetAllBalances(ctx, tc.addr) + iUTokenSupply := app.LeverageKeeper.GetAllUTokenSupply(ctx) + iMeTokenBalance, err := k.IndexBalances(meTokenDenom) + require.NoError(t, err) + + prices, err := k.Prices(index) + require.NoError(t, err) + + // verify the outputs of swap function + resp, err := msgServer.Swap(ctx, msg) + require.NoError(t, err, tc.name) + + // final state + fUserBalance := app.BankKeeper.GetAllBalances(ctx, tc.addr) + fUTokenSupply := app.LeverageKeeper.GetAllUTokenSupply(ctx) + fMeTokenBalance, err := k.IndexBalances(meTokenDenom) + require.NoError(t, err) + + verifySwap( + t, + tc, + index, + iUserBalance, + fUserBalance, + iUTokenSupply, + fUTokenSupply, + iMeTokenBalance, + fMeTokenBalance, + prices, + *resp, + ) + } + } + +} + +func TestMsgServer_Swap_AfterAddingAssetToIndex(t *testing.T) { + index := mocks.StableIndex(mocks.MeUSDDenom) + + s := initKeeperTestSuite(t, nil, nil) + msgServer, ctx, app := s.msgServer, s.ctx, s.app + + _, err := msgServer.GovUpdateRegistry( + ctx, &metoken.MsgGovUpdateRegistry{ + Authority: app.GovKeeper.GetGovernanceAccount(s.ctx).GetAddress().String(), + AddIndex: []metoken.Index{index}, + UpdateIndex: nil, + }, + ) + require.NoError(t, err) + + // create and fund a user with 1000 USDT, 5000 USDC, 20000 IST and 7.674 ETH + user := s.newAccount( + t, + coin.New(mocks.USDTBaseDenom, 10000_000000), + coin.New(mocks.USDCBaseDenom, 5000_000000), + coin.New(mocks.ISTBaseDenom, 20000_000000), + coin.New(mocks.ETHBaseDenom, 7_674000000000000000), + ) + + tcs := []testCase{ + { + "valid - first swap 7546 USDT", + user, + coin.New(mocks.USDTBaseDenom, 7546_000000), + mocks.MeUSDDenom, + "", + }, + { + "valid - swap 1432.77 USDC", + user, + coin.New(mocks.USDCBaseDenom, 1432_770000), + mocks.MeUSDDenom, + "", + }, + { + "valid - swap 15600.82 IST", + user, + coin.New(mocks.ISTBaseDenom, 15600_820000), + mocks.MeUSDDenom, + "", + }, + } + + for _, tc := range tcs { + msg := &metoken.MsgSwap{ + User: tc.addr.String(), + Asset: tc.asset, + MetokenDenom: tc.denom, + } + if len(tc.errMsg) > 0 { + _, err := msgServer.Swap(ctx, msg) + assert.ErrorContains(t, err, tc.errMsg) + } else { + meTokenDenom := tc.denom + k := app.MetokenKeeperB.Keeper(&ctx) + + // initial state + iUserBalance := app.BankKeeper.GetAllBalances(ctx, tc.addr) + iUTokenSupply := app.LeverageKeeper.GetAllUTokenSupply(ctx) + iMeTokenBalance, err := k.IndexBalances(meTokenDenom) + require.NoError(t, err) + + prices, err := k.Prices(index) + require.NoError(t, err) + + // verify the outputs of swap function + resp, err := msgServer.Swap(ctx, msg) + require.NoError(t, err, tc.name) + + // final state + fUserBalance := app.BankKeeper.GetAllBalances(ctx, tc.addr) + fUTokenSupply := app.LeverageKeeper.GetAllUTokenSupply(ctx) + fMeTokenBalance, err := k.IndexBalances(meTokenDenom) + require.NoError(t, err) + + verifySwap( + t, + tc, + index, + iUserBalance, + fUserBalance, + iUTokenSupply, + fUTokenSupply, + iMeTokenBalance, + fMeTokenBalance, + prices, + *resp, + ) + } + } + + // after initial swaps ETH is added to the index and target_allocation is recalculated + for i := 0; i < len(index.AcceptedAssets); i++ { + index.AcceptedAssets[i].TargetAllocation = sdk.MustNewDecFromStr("0.25") + } + index.AcceptedAssets = append( + index.AcceptedAssets, + metoken.NewAcceptedAsset(mocks.ETHBaseDenom, sdk.MustNewDecFromStr("0.2"), sdk.MustNewDecFromStr("0.25")), + ) + + _, err = msgServer.GovUpdateRegistry( + ctx, &metoken.MsgGovUpdateRegistry{ + Authority: app.GovKeeper.GetGovernanceAccount(s.ctx).GetAddress().String(), + AddIndex: nil, + UpdateIndex: []metoken.Index{index}, + }, + ) + require.NoError(t, err) + + tcs = []testCase{ + { + "valid - swap 1243.56 USDT", + user, + coin.New(mocks.USDTBaseDenom, 1243_560000), + mocks.MeUSDDenom, + "", + }, + { + "valid - swap 6.312 ETH", + user, + coin.New(mocks.ETHBaseDenom, 6_312000000000000000), + mocks.MeUSDDenom, + "", + }, + { + "valid - swap 0.312 ETH", + user, + coin.New(mocks.ETHBaseDenom, 312000000000000000), + mocks.MeUSDDenom, + "", + }, + { + "valid - swap 2700 USDC", + user, + coin.New(mocks.USDCBaseDenom, 2700_000000), + mocks.MeUSDDenom, + "", + }, + { + "valid - swap 1000.07 IST", + user, + coin.New(mocks.ISTBaseDenom, 1000_070000), + mocks.MeUSDDenom, + "", + }, + } + + for _, tc := range tcs { + msg := &metoken.MsgSwap{ + User: tc.addr.String(), + Asset: tc.asset, + MetokenDenom: tc.denom, + } + if len(tc.errMsg) > 0 { + _, err := msgServer.Swap(ctx, msg) + assert.ErrorContains(t, err, tc.errMsg) + } else { + meTokenDenom := tc.denom + k := app.MetokenKeeperB.Keeper(&ctx) + + // initial state + iUserBalance := app.BankKeeper.GetAllBalances(ctx, tc.addr) + iUTokenSupply := app.LeverageKeeper.GetAllUTokenSupply(ctx) + iMeTokenBalance, err := k.IndexBalances(meTokenDenom) + require.NoError(t, err) + + prices, err := k.Prices(index) + require.NoError(t, err) + + // verify the outputs of swap function + resp, err := msgServer.Swap(ctx, msg) + require.NoError(t, err, tc.name) + + // final state + fUserBalance := app.BankKeeper.GetAllBalances(ctx, tc.addr) + fUTokenSupply := app.LeverageKeeper.GetAllUTokenSupply(ctx) + fMeTokenBalance, err := k.IndexBalances(meTokenDenom) + require.NoError(t, err) + + verifySwap( + t, + tc, + index, + iUserBalance, + fUserBalance, + iUTokenSupply, + fUTokenSupply, + iMeTokenBalance, + fMeTokenBalance, + prices, + *resp, + ) + } + } +} + +func TestMsgServer_Swap_Depegging(t *testing.T) { + index := mocks.StableIndex(mocks.MeUSDDenom) + + s := initKeeperTestSuite(t, nil, nil) + msgServer, ctx, app := s.msgServer, s.ctx, s.app + + _, err := msgServer.GovUpdateRegistry( + ctx, &metoken.MsgGovUpdateRegistry{ + Authority: app.GovKeeper.GetGovernanceAccount(s.ctx).GetAddress().String(), + AddIndex: []metoken.Index{index}, + UpdateIndex: nil, + }, + ) + require.NoError(t, err) + + // create and fund a user with 10000 USDT, 10000 USDC, 10000 IST + user := s.newAccount( + t, + coin.New(mocks.USDTBaseDenom, 10000_000000), + coin.New(mocks.USDCBaseDenom, 10000_000000), + coin.New(mocks.ISTBaseDenom, 10000_000000), + ) + + tcs := []testCase{ + { + "valid - first swap 343.055 IST", + user, + coin.New(mocks.ISTBaseDenom, 343_055000), + mocks.MeUSDDenom, + "", + }, + { + "valid - swap 12.77 IST", + user, + coin.New(mocks.ISTBaseDenom, 12_770000), + mocks.MeUSDDenom, + "", + }, + { + "valid - swap 48.33 USDC", + user, + coin.New(mocks.USDCBaseDenom, 48_330000), + mocks.MeUSDDenom, + "", + }, + } + + for _, tc := range tcs { + msg := &metoken.MsgSwap{ + User: tc.addr.String(), + Asset: tc.asset, + MetokenDenom: tc.denom, + } + if len(tc.errMsg) > 0 { + _, err := msgServer.Swap(ctx, msg) + assert.ErrorContains(t, err, tc.errMsg) + } else { + meTokenDenom := tc.denom + k := app.MetokenKeeperB.Keeper(&ctx) + + // initial state + iUserBalance := app.BankKeeper.GetAllBalances(ctx, tc.addr) + iUTokenSupply := app.LeverageKeeper.GetAllUTokenSupply(ctx) + iMeTokenBalance, err := k.IndexBalances(meTokenDenom) + require.NoError(t, err) + + prices, err := k.Prices(index) + require.NoError(t, err) + + // verify the outputs of swap function + resp, err := msgServer.Swap(ctx, msg) + require.NoError(t, err, tc.name) + + // final state + fUserBalance := app.BankKeeper.GetAllBalances(ctx, tc.addr) + fUTokenSupply := app.LeverageKeeper.GetAllUTokenSupply(ctx) + fMeTokenBalance, err := k.IndexBalances(meTokenDenom) + require.NoError(t, err) + + verifySwap( + t, + tc, + index, + iUserBalance, + fUserBalance, + iUTokenSupply, + fUTokenSupply, + iMeTokenBalance, + fMeTokenBalance, + prices, + *resp, + ) + } + } + + // after initial swaps IST price is dropped to 0.64 USD + oracleMock := mocks.NewMockOracleKeeper() + oracleMock.AllMedianPricesFunc.SetDefaultHook( + func(ctx sdk.Context) otypes.Prices { + prices := otypes.Prices{} + median := otypes.Price{ + ExchangeRateTuple: otypes.NewExchangeRateTuple( + mocks.USDTSymbolDenom, + mocks.USDTPrice, + ), + BlockNum: uint64(1), + } + prices = append(prices, median) + + median = otypes.Price{ + ExchangeRateTuple: otypes.NewExchangeRateTuple( + mocks.USDCSymbolDenom, + mocks.USDCPrice, + ), + BlockNum: uint64(1), + } + prices = append(prices, median) + + median = otypes.Price{ + ExchangeRateTuple: otypes.NewExchangeRateTuple( + mocks.ISTSymbolDenom, + sdk.MustNewDecFromStr("0.64"), + ), + BlockNum: uint64(1), + } + prices = append(prices, median) + + return prices + }, + ) + + kb := keeper.NewKeeperBuilder( + app.AppCodec(), + app.GetKey(metoken.ModuleName), + app.BankKeeper, + app.LeverageKeeper, + oracleMock, + ) + app.MetokenKeeperB = kb + msgServer = keeper.NewMsgServerImpl(app.MetokenKeeperB) + + tcs = []testCase{ + { + "valid - swap 1243.56 USDT", + user, + coin.New(mocks.USDTBaseDenom, 1243_560000), + mocks.MeUSDDenom, + "", + }, + { + "valid - swap 2000 IST", + user, + coin.New(mocks.ISTBaseDenom, 2000_000000), + mocks.MeUSDDenom, + "", + }, + { + "valid - swap 1000.07 IST", + user, + coin.New(mocks.ISTBaseDenom, 1000_070000), + mocks.MeUSDDenom, + "", + }, + { + "valid - swap 753.011 USDC", + user, + coin.New(mocks.USDCBaseDenom, 753_011000), + mocks.MeUSDDenom, + "", + }, + } + + for _, tc := range tcs { + msg := &metoken.MsgSwap{ + User: tc.addr.String(), + Asset: tc.asset, + MetokenDenom: tc.denom, + } + if len(tc.errMsg) > 0 { + _, err := msgServer.Swap(ctx, msg) + assert.ErrorContains(t, err, tc.errMsg) + } else { + meTokenDenom := tc.denom + k := app.MetokenKeeperB.Keeper(&ctx) + + // initial state + iUserBalance := app.BankKeeper.GetAllBalances(ctx, tc.addr) + iUTokenSupply := app.LeverageKeeper.GetAllUTokenSupply(ctx) + iMeTokenBalance, err := k.IndexBalances(meTokenDenom) + require.NoError(t, err) + + prices, err := k.Prices(index) + require.NoError(t, err) + + // verify the outputs of swap function + resp, err := msgServer.Swap(ctx, msg) + require.NoError(t, err, tc.name) + + // final state + fUserBalance := app.BankKeeper.GetAllBalances(ctx, tc.addr) + fUTokenSupply := app.LeverageKeeper.GetAllUTokenSupply(ctx) + fMeTokenBalance, err := k.IndexBalances(meTokenDenom) + require.NoError(t, err) + + verifySwap( + t, + tc, + index, + iUserBalance, + fUserBalance, + iUTokenSupply, + fUTokenSupply, + iMeTokenBalance, + fMeTokenBalance, + prices, + *resp, + ) + } + } + + // after some swaps with depegged price, all is back to normal + oracleMock.AllMedianPricesFunc.SetDefaultHook(mocks.ValidPricesFunc()) + + kb = keeper.NewKeeperBuilder( + app.AppCodec(), + app.GetKey(metoken.ModuleName), + app.BankKeeper, + app.LeverageKeeper, + oracleMock, + ) + app.MetokenKeeperB = kb + msgServer = keeper.NewMsgServerImpl(app.MetokenKeeperB) + + tcs = []testCase{ + { + "valid - swap 312.04 USDT", + user, + coin.New(mocks.USDTBaseDenom, 312_040000), + mocks.MeUSDDenom, + "", + }, + { + "valid - swap 145 IST", + user, + coin.New(mocks.ISTBaseDenom, 145_000000), + mocks.MeUSDDenom, + "", + }, + { + "valid - swap 255.478 USDT", + user, + coin.New(mocks.USDTBaseDenom, 255_478000), + mocks.MeUSDDenom, + "", + }, + { + "valid - swap 753.011 USDC", + user, + coin.New(mocks.USDCBaseDenom, 753_011000), + mocks.MeUSDDenom, + "", + }, + } + + for _, tc := range tcs { + msg := &metoken.MsgSwap{ + User: tc.addr.String(), + Asset: tc.asset, + MetokenDenom: tc.denom, + } + if len(tc.errMsg) > 0 { + _, err := msgServer.Swap(ctx, msg) + assert.ErrorContains(t, err, tc.errMsg) + } else { + meTokenDenom := tc.denom + k := app.MetokenKeeperB.Keeper(&ctx) + + // initial state + iUserBalance := app.BankKeeper.GetAllBalances(ctx, tc.addr) + iUTokenSupply := app.LeverageKeeper.GetAllUTokenSupply(ctx) + iMeTokenBalance, err := k.IndexBalances(meTokenDenom) + require.NoError(t, err) + + prices, err := k.Prices(index) + require.NoError(t, err) + + // verify the outputs of swap function + resp, err := msgServer.Swap(ctx, msg) + require.NoError(t, err, tc.name) + + // final state + fUserBalance := app.BankKeeper.GetAllBalances(ctx, tc.addr) + fUTokenSupply := app.LeverageKeeper.GetAllUTokenSupply(ctx) + fMeTokenBalance, err := k.IndexBalances(meTokenDenom) + require.NoError(t, err) + + verifySwap( + t, + tc, + index, + iUserBalance, + fUserBalance, + iUTokenSupply, + fUTokenSupply, + iMeTokenBalance, + fMeTokenBalance, + prices, + *resp, + ) + } + } +} + +func verifySwap( + t *testing.T, tc testCase, index metoken.Index, + iUserBalance, fUserBalance, iUTokenSupply, fUTokenSupply sdk.Coins, + iMeTokenBalance, fMeTokenBalance metoken.IndexBalances, + prices metoken.IndexPrices, resp metoken.MsgSwapResponse, +) { + denom, meTokenDenom := tc.asset.Denom, tc.denom + + // initial state + assetPrice, err := prices.Price(denom) + assert.NilError(t, err) + i, iAssetBalance := iMeTokenBalance.AssetBalance(denom) + assert.Check(t, i >= 0) + assetSupply := iAssetBalance.Leveraged.Add(iAssetBalance.Reserved) + meTokenPrice, err := prices.Price(meTokenDenom) + assert.NilError(t, err) + + assetExponentFactorVsUSD, err := metoken.ExponentFactor(assetPrice.Exponent, 0) + assert.NilError(t, err) + decAssetSupply := assetExponentFactorVsUSD.MulInt(assetSupply) + assetValue := decAssetSupply.Mul(assetPrice.Price) + + meTokenExponentFactor, err := metoken.ExponentFactor(meTokenPrice.Exponent, 0) + assert.NilError(t, err) + decMeTokenSupply := meTokenExponentFactor.MulInt(iMeTokenBalance.MetokenSupply.Amount) + meTokenValue := decMeTokenSupply.Mul(meTokenPrice.Price) + + // current_allocation = asset_value / total_value + // swap_delta_allocation = (current_allocation - target_allocation) / target_allocation + currentAllocation, swapDeltaAllocation := sdk.ZeroDec(), sdk.ZeroDec() + i, aa := index.AcceptedAsset(denom) + assert.Check(t, i >= 0) + targetAllocation := aa.TargetAllocation + + if assetSupply.IsZero() { + swapDeltaAllocation = currentAllocation.Sub(targetAllocation) + } else { + currentAllocation = assetValue.Quo(meTokenValue) + swapDeltaAllocation = currentAllocation.Sub(targetAllocation).Quo(targetAllocation) + } + + // fee = delta_allocation * balanced_fee + balanced_fee + fee := swapDeltaAllocation.Mul(index.Fee.BalancedFee).Add(index.Fee.BalancedFee) + if fee.LT(index.Fee.MinFee) { + fee = index.Fee.MinFee + } + if fee.GT(index.Fee.MaxFee) { + fee = index.Fee.MaxFee + } + + // if current_allocation = 0, fee = min_fee + if !currentAllocation.IsPositive() { + fee = index.Fee.MinFee + } + + // expected_fee = fee * amount + expectedFee := sdk.NewCoin(denom, fee.MulInt(tc.asset.Amount).TruncateInt()) + + // amount_to_swap = swap_amount - fee + amountToSwap := tc.asset.Amount.Sub(expectedFee.Amount) + + // swap_exchange_rate = asset_price / metoken_price + exchangeRate := assetPrice.Price.Quo(meTokenPrice.Price) + + assetExponentFactorVsMeToken, err := prices.ExponentFactor(denom, meTokenDenom) + assert.NilError(t, err) + + // expected_metokens = amount_to_swap * exchange_rate * exponent_factor + expectedMeTokens := sdk.NewCoin( + meTokenDenom, + exchangeRate.MulInt(amountToSwap).Mul(assetExponentFactorVsMeToken).TruncateInt(), + ) + + // calculating reserved and leveraged + expectedReserved := sdk.NewCoin( + denom, + aa.ReservePortion.MulInt(amountToSwap).TruncateInt(), + ) + expectedLeveraged := sdk.NewCoin(denom, amountToSwap.Sub(expectedReserved.Amount)) + + // verify the outputs of swap function + require.Equal(t, expectedFee, resp.Fee, tc.name) + require.Equal(t, expectedMeTokens, resp.Returned, tc.name) + + // verify token balance decreased and meToken balance increased by the expected amounts + require.Equal( + t, + iUserBalance.Sub(tc.asset).Add(expectedMeTokens), + fUserBalance, + tc.name, + "token balance", + ) + // verify uToken assetSupply increased by the expected amount + require.Equal( + t, + iUTokenSupply.Add(sdk.NewCoin("u/"+expectedLeveraged.Denom, expectedLeveraged.Amount)), + fUTokenSupply, + tc.name, + "uToken assetSupply", + ) + // reserved + leveraged + fee must be = to total amount supplied by the user for the swap + require.Equal(t, expectedReserved.Add(expectedLeveraged).Add(expectedFee), tc.asset) + + // meToken assetSupply is increased by the expected amount + require.Equal( + t, + iMeTokenBalance.MetokenSupply.Add(expectedMeTokens), + fMeTokenBalance.MetokenSupply, + tc.name, + "meToken assetSupply", + ) + + i, fAssetBalance := fMeTokenBalance.AssetBalance(denom) + assert.Check(t, i >= 0) + require.Equal( + t, + iAssetBalance.Reserved.Add(expectedReserved.Amount), + fAssetBalance.Reserved, + "reserved", + ) + require.Equal( + t, + iAssetBalance.Leveraged.Add(expectedLeveraged.Amount), + fAssetBalance.Leveraged, + "leveraged", + ) + require.Equal( + t, + iAssetBalance.Fees.Add(expectedFee.Amount), + fAssetBalance.Fees, + "fee", + ) +} + +func TestMsgServer_Redeem(t *testing.T) { + index := mocks.StableIndex(mocks.MeUSDDenom) + + s := initKeeperTestSuite(t, nil, nil) + msgServer, ctx, app := s.msgServer, s.ctx, s.app + + _, err := msgServer.GovUpdateRegistry( + ctx, &metoken.MsgGovUpdateRegistry{ + Authority: app.GovKeeper.GetGovernanceAccount(s.ctx).GetAddress().String(), + AddIndex: []metoken.Index{index}, + UpdateIndex: nil, + }, + ) + require.NoError(t, err) + + // create and fund a user with 1000 USDT, 1000 USDC and 1000 IST + user := s.newAccount( + t, + coin.New(mocks.USDTBaseDenom, 1000_000000), + coin.New(mocks.USDCBaseDenom, 1000_000000), + coin.New(mocks.ISTBaseDenom, 1000_000000), + ) + + // swap 547 USDT, 200 USDC and 740 IST to have an initial meUSD balance + swaps := []*metoken.MsgSwap{ + { + User: user.String(), + Asset: sdk.NewCoin(mocks.USDTBaseDenom, sdkmath.NewInt(547_000000)), + MetokenDenom: mocks.MeUSDDenom, + }, + { + User: user.String(), + Asset: sdk.NewCoin(mocks.USDCBaseDenom, sdkmath.NewInt(200_000000)), + MetokenDenom: mocks.MeUSDDenom, + }, + { + User: user.String(), + Asset: sdk.NewCoin(mocks.ISTBaseDenom, sdkmath.NewInt(740_000000)), + MetokenDenom: mocks.MeUSDDenom, + }, + } + + for _, swap := range swaps { + _, err := msgServer.Swap(ctx, swap) + require.NoError(t, err) + } + + tcs := []testCase{ + { + "invalid user address", + sdk.AccAddress{}, + sdk.Coin{}, + "", + "empty address string is not allowed", + }, + { + "invalid meToken", + user, + sdk.Coin{ + Denom: "???", + Amount: sdkmath.ZeroInt(), + }, + "", + "invalid denom", + }, + { + "invalid asset denom", + user, + coin.New(mocks.MeUSDDenom, 100_000000), + "???", + "invalid denom", + }, + { + "valid - redemption 155.9876 meUSD for IST", + user, + coin.New(mocks.MeUSDDenom, 155_987600), + mocks.ISTBaseDenom, + "", + }, + { + "valid - redemption 750.56 meUSD for USDC - but not enough USDC", + user, + coin.New(mocks.MeUSDDenom, 750_560000), + mocks.USDCBaseDenom, + "not enough", + }, + { + "valid - redemption 187 meUSD for ist", + user, + coin.New(mocks.MeUSDDenom, 187_000000), + mocks.ISTBaseDenom, + "", + }, + { + "valid - redemption 468.702000 meUSD for USDT", + user, + coin.New(mocks.MeUSDDenom, 468_702000), + mocks.USDTBaseDenom, + "", + }, + { + "invalid - index doesn't exist", + user, + coin.New("me/EUR", 100_000000), + "me/EUR", + "index me/EUR not found", + }, + { + "valid - redemption 1000.13 meUSD for IST - but not enough IST", + user, + coin.New(mocks.MeUSDDenom, 1000_130000), + mocks.ISTBaseDenom, + "not enough", + }, + } + + for _, tc := range tcs { + msg := &metoken.MsgRedeem{ + User: tc.addr.String(), + Metoken: tc.asset, + AssetDenom: tc.denom, + } + if len(tc.errMsg) > 0 { + _, err := msgServer.Redeem(ctx, msg) + assert.ErrorContains(t, err, tc.errMsg, tc.name) + } else { + meTokenDenom := tc.asset.Denom + k := app.MetokenKeeperB.Keeper(&ctx) + + // initial state + iUserBalance := app.BankKeeper.GetAllBalances(ctx, tc.addr) + iUTokenSupply := app.LeverageKeeper.GetAllUTokenSupply(ctx) + iMeTokenBalance, err := k.IndexBalances(meTokenDenom) + require.NoError(t, err) + + prices, err := k.Prices(index) + require.NoError(t, err) + + // verify the outputs of redeem function + resp, err := msgServer.Redeem(ctx, msg) + require.NoError(t, err, tc.name) + + // final state + fUserBalance := app.BankKeeper.GetAllBalances(ctx, tc.addr) + fUTokenSupply := app.LeverageKeeper.GetAllUTokenSupply(ctx) + fMeTokenBalance, err := k.IndexBalances(meTokenDenom) + require.NoError(t, err) + + verifyRedeem( + t, + tc, + index, + iUserBalance, + fUserBalance, + iUTokenSupply, + fUTokenSupply, + iMeTokenBalance, + fMeTokenBalance, + prices, + *resp, + ) + } + } +} + +func TestMsgServer_Redeem_NonStableAssets_DiffExponents(t *testing.T) { + index := mocks.NonStableIndex(mocks.MeNonStableDenom) + + s := initKeeperTestSuite(t, nil, nil) + msgServer, ctx, app := s.msgServer, s.ctx, s.app + + _, err := msgServer.GovUpdateRegistry( + ctx, &metoken.MsgGovUpdateRegistry{ + Authority: app.GovKeeper.GetGovernanceAccount(s.ctx).GetAddress().String(), + AddIndex: []metoken.Index{index}, + UpdateIndex: nil, + }, + ) + require.NoError(t, err) + + // create and fund a user with 10000 USDT, 1.431 WBTC, 2.876 ETH + user := s.newAccount( + t, + coin.New(mocks.USDTBaseDenom, 10000_000000), + coin.New(mocks.WBTCBaseDenom, 21_43100000), + coin.New(mocks.ETHBaseDenom, 2_876000000000000000), + ) + + // swap 1547 USDT, 20.57686452 WBTC and 0.7855 ETH to have an initial meNonStable balance + swaps := []*metoken.MsgSwap{ + { + User: user.String(), + Asset: sdk.NewCoin(mocks.USDTBaseDenom, sdkmath.NewInt(1547_000000)), + MetokenDenom: mocks.MeNonStableDenom, + }, + { + User: user.String(), + Asset: sdk.NewCoin(mocks.WBTCBaseDenom, sdkmath.NewInt(20_57686452)), + MetokenDenom: mocks.MeNonStableDenom, + }, + { + User: user.String(), + Asset: sdk.NewCoin(mocks.ETHBaseDenom, sdkmath.NewInt(785500000000000000)), + MetokenDenom: mocks.MeNonStableDenom, + }, + } + + for _, swap := range swaps { + resp, err := msgServer.Swap(ctx, swap) + require.NoError(t, err) + require.NotNil(t, resp) + } + + tcs := []testCase{ + { + "valid - redeem 2.182736 meNonStable for WBTC", + user, + coin.New(mocks.MeNonStableDenom, 2_18273600), + mocks.WBTCBaseDenom, + "", + }, + { + "valid - redeem 0.05879611 meNonStable ETH", + user, + coin.New(mocks.MeNonStableDenom, 5879611), + mocks.ETHBaseDenom, + "", + }, + { + "valid - redeem 0.1 meNonStable USDT", + user, + coin.New(mocks.MeNonStableDenom, 10000000), + mocks.USDTBaseDenom, + "", + }, + { + "valid - redeem 12 meNonStable for WBTC", + user, + coin.New(mocks.MeNonStableDenom, 12_00000000), + mocks.WBTCBaseDenom, + "", + }, + { + "valid - redeem 2.182736 meNonStable for USDT - not enough USDT", + user, + coin.New(mocks.MeNonStableDenom, 2_18273600), + mocks.USDTBaseDenom, + "not enough", + }, + } + + for _, tc := range tcs { + msg := &metoken.MsgRedeem{ + User: tc.addr.String(), + Metoken: tc.asset, + AssetDenom: tc.denom, + } + if len(tc.errMsg) > 0 { + _, err := msgServer.Redeem(ctx, msg) + assert.ErrorContains(t, err, tc.errMsg) + } else { + meTokenDenom := tc.asset.Denom + k := app.MetokenKeeperB.Keeper(&ctx) + + // initial state + iUserBalance := app.BankKeeper.GetAllBalances(ctx, tc.addr) + iUTokenSupply := app.LeverageKeeper.GetAllUTokenSupply(ctx) + iMeTokenBalance, err := k.IndexBalances(meTokenDenom) + require.NoError(t, err) + + prices, err := k.Prices(index) + require.NoError(t, err) + + // verify the outputs of redeem function + resp, err := msgServer.Redeem(ctx, msg) + require.NoError(t, err, tc.name) + + // final state + fUserBalance := app.BankKeeper.GetAllBalances(ctx, tc.addr) + fUTokenSupply := app.LeverageKeeper.GetAllUTokenSupply(ctx) + fMeTokenBalance, err := k.IndexBalances(meTokenDenom) + require.NoError(t, err) + + verifyRedeem( + t, + tc, + index, + iUserBalance, + fUserBalance, + iUTokenSupply, + fUTokenSupply, + iMeTokenBalance, + fMeTokenBalance, + prices, + *resp, + ) + } + } +} + +func TestMsgServer_Redeem_Depegging(t *testing.T) { + index := mocks.StableIndex(mocks.MeUSDDenom) + + s := initKeeperTestSuite(t, nil, nil) + msgServer, ctx, app := s.msgServer, s.ctx, s.app + + _, err := msgServer.GovUpdateRegistry( + ctx, &metoken.MsgGovUpdateRegistry{ + Authority: app.GovKeeper.GetGovernanceAccount(s.ctx).GetAddress().String(), + AddIndex: []metoken.Index{index}, + UpdateIndex: nil, + }, + ) + require.NoError(t, err) + + // create and fund a user with 10000 USDT, 10000 USDC, 10000 IST + user := s.newAccount( + t, + coin.New(mocks.USDTBaseDenom, 10000_000000), + coin.New(mocks.USDCBaseDenom, 10000_000000), + coin.New(mocks.ISTBaseDenom, 10000_000000), + ) + + // swap 5000 USDT, 3500 USDC an initial meUSD balance + swaps := []*metoken.MsgSwap{ + { + User: user.String(), + Asset: sdk.NewCoin(mocks.USDTBaseDenom, sdkmath.NewInt(5000_000000)), + MetokenDenom: mocks.MeUSDDenom, + }, + { + User: user.String(), + Asset: sdk.NewCoin(mocks.USDCBaseDenom, sdkmath.NewInt(3500_000000)), + MetokenDenom: mocks.MeUSDDenom, + }, + } + + for _, swap := range swaps { + _, err := msgServer.Swap(ctx, swap) + require.NoError(t, err) + } + + // after initial swaps USDT price is dropped to 0.73 USD + oracleMock := mocks.NewMockOracleKeeper() + oracleMock.AllMedianPricesFunc.SetDefaultHook( + func(ctx sdk.Context) otypes.Prices { + prices := otypes.Prices{} + median := otypes.Price{ + ExchangeRateTuple: otypes.NewExchangeRateTuple( + mocks.USDTSymbolDenom, + sdk.MustNewDecFromStr("0.73"), + ), + BlockNum: uint64(1), + } + prices = append(prices, median) + + median = otypes.Price{ + ExchangeRateTuple: otypes.NewExchangeRateTuple( + mocks.USDCSymbolDenom, + mocks.USDCPrice, + ), + BlockNum: uint64(1), + } + prices = append(prices, median) + + median = otypes.Price{ + ExchangeRateTuple: otypes.NewExchangeRateTuple( + mocks.ISTSymbolDenom, + mocks.ISTPrice, + ), + BlockNum: uint64(1), + } + prices = append(prices, median) + + return prices + }, + ) + + kb := keeper.NewKeeperBuilder( + app.AppCodec(), + app.GetKey(metoken.ModuleName), + app.BankKeeper, + app.LeverageKeeper, + oracleMock, + ) + app.MetokenKeeperB = kb + msgServer = keeper.NewMsgServerImpl(app.MetokenKeeperB) + + tcs := []testCase{ + { + "valid - redeem 100 meUSD for IST", + user, + coin.New(mocks.MeUSDDenom, 100_000000), + mocks.ISTBaseDenom, + "not enough", + }, + { + "valid - redeem 1000 meUSD for USDC", + user, + coin.New(mocks.MeUSDDenom, 1000_000000), + mocks.USDCBaseDenom, + "", + }, + { + "valid - redeem 2500 meUSD for USDT", + user, + coin.New(mocks.MeUSDDenom, 2500_000000), + mocks.USDTBaseDenom, + "", + }, + { + "valid - redeem 2200 meUSD for USDC", + user, + coin.New(mocks.MeUSDDenom, 2200_000000), + mocks.USDCBaseDenom, + "", + }, + } + + for _, tc := range tcs { + msg := &metoken.MsgRedeem{ + User: tc.addr.String(), + Metoken: tc.asset, + AssetDenom: tc.denom, + } + if len(tc.errMsg) > 0 { + _, err := msgServer.Redeem(ctx, msg) + assert.ErrorContains(t, err, tc.errMsg) + } else { + meTokenDenom := tc.asset.Denom + k := app.MetokenKeeperB.Keeper(&ctx) + + // initial state + iUserBalance := app.BankKeeper.GetAllBalances(ctx, tc.addr) + iUTokenSupply := app.LeverageKeeper.GetAllUTokenSupply(ctx) + iMeTokenBalance, err := k.IndexBalances(meTokenDenom) + require.NoError(t, err) + + prices, err := k.Prices(index) + require.NoError(t, err) + + // verify the outputs of redeem function + resp, err := msgServer.Redeem(ctx, msg) + require.NoError(t, err, tc.name) + + // final state + fUserBalance := app.BankKeeper.GetAllBalances(ctx, tc.addr) + fUTokenSupply := app.LeverageKeeper.GetAllUTokenSupply(ctx) + fMeTokenBalance, err := k.IndexBalances(meTokenDenom) + require.NoError(t, err) + + verifyRedeem( + t, + tc, + index, + iUserBalance, + fUserBalance, + iUTokenSupply, + fUTokenSupply, + iMeTokenBalance, + fMeTokenBalance, + prices, + *resp, + ) + } + } + + // after some redemptions with depegged price, all is back to normal + oracleMock.AllMedianPricesFunc.SetDefaultHook(mocks.ValidPricesFunc()) + + kb = keeper.NewKeeperBuilder( + app.AppCodec(), + app.GetKey(metoken.ModuleName), + app.BankKeeper, + app.LeverageKeeper, + oracleMock, + ) + app.MetokenKeeperB = kb + msgServer = keeper.NewMsgServerImpl(app.MetokenKeeperB) + + tcs = []testCase{ + { + "valid - swap 312.04 USDT", + user, + coin.New(mocks.USDTBaseDenom, 312_040000), + mocks.MeUSDDenom, + "", + }, + { + "valid - swap 145 IST", + user, + coin.New(mocks.ISTBaseDenom, 145_000000), + mocks.MeUSDDenom, + "", + }, + { + "valid - swap 255.478 USDT", + user, + coin.New(mocks.USDTBaseDenom, 255_478000), + mocks.MeUSDDenom, + "", + }, + { + "valid - swap 753.011 USDC", + user, + coin.New(mocks.USDCBaseDenom, 753_011000), + mocks.MeUSDDenom, + "", + }, + } + + for _, tc := range tcs { + msg := &metoken.MsgSwap{ + User: tc.addr.String(), + Asset: tc.asset, + MetokenDenom: tc.denom, + } + if len(tc.errMsg) > 0 { + _, err := msgServer.Swap(ctx, msg) + assert.ErrorContains(t, err, tc.errMsg) + } else { + meTokenDenom := tc.denom + k := app.MetokenKeeperB.Keeper(&ctx) + + // initial state + iUserBalance := app.BankKeeper.GetAllBalances(ctx, tc.addr) + iUTokenSupply := app.LeverageKeeper.GetAllUTokenSupply(ctx) + iMeTokenBalance, err := k.IndexBalances(meTokenDenom) + require.NoError(t, err) + + prices, err := k.Prices(index) + require.NoError(t, err) + + // verify the outputs of swap function + resp, err := msgServer.Swap(ctx, msg) + require.NoError(t, err, tc.name) + + // final state + fUserBalance := app.BankKeeper.GetAllBalances(ctx, tc.addr) + fUTokenSupply := app.LeverageKeeper.GetAllUTokenSupply(ctx) + fMeTokenBalance, err := k.IndexBalances(meTokenDenom) + require.NoError(t, err) + + verifySwap( + t, + tc, + index, + iUserBalance, + fUserBalance, + iUTokenSupply, + fUTokenSupply, + iMeTokenBalance, + fMeTokenBalance, + prices, + *resp, + ) + } + } + + // redeem all the available meUSD in the balance to confirm we have sufficient liquidity to do it + tcs = []testCase{ + { + "valid - redeem 1584.411571 meUSD for USDT", + user, + coin.New(mocks.MeUSDDenom, 1584_411571), + mocks.USDTBaseDenom, + "", + }, + { + "valid - redeem 934.139005 meUSD for USDC", + user, + coin.New(mocks.MeUSDDenom, 934_139005), + mocks.USDCBaseDenom, + "", + }, + { + "valid - redeem 118.125618 meUSD for IST", + user, + coin.New(mocks.MeUSDDenom, 118_125618), + mocks.ISTBaseDenom, + "", + }, + } + + for _, tc := range tcs { + msg := &metoken.MsgRedeem{ + User: tc.addr.String(), + Metoken: tc.asset, + AssetDenom: tc.denom, + } + if len(tc.errMsg) > 0 { + _, err := msgServer.Redeem(ctx, msg) + assert.ErrorContains(t, err, tc.errMsg) + } else { + meTokenDenom := tc.asset.Denom + k := app.MetokenKeeperB.Keeper(&ctx) + + // initial state + iUserBalance := app.BankKeeper.GetAllBalances(ctx, tc.addr) + iUTokenSupply := app.LeverageKeeper.GetAllUTokenSupply(ctx) + iMeTokenBalance, err := k.IndexBalances(meTokenDenom) + require.NoError(t, err) + + prices, err := k.Prices(index) + require.NoError(t, err) + + // verify the outputs of redeem function + resp, err := msgServer.Redeem(ctx, msg) + require.NoError(t, err, tc.name) + + // final state + fUserBalance := app.BankKeeper.GetAllBalances(ctx, tc.addr) + fUTokenSupply := app.LeverageKeeper.GetAllUTokenSupply(ctx) + fMeTokenBalance, err := k.IndexBalances(meTokenDenom) + require.NoError(t, err) + + verifyRedeem( + t, + tc, + index, + iUserBalance, + fUserBalance, + iUTokenSupply, + fUTokenSupply, + iMeTokenBalance, + fMeTokenBalance, + prices, + *resp, + ) + } + } +} + +func verifyRedeem( + t *testing.T, tc testCase, index metoken.Index, + iUserBalance, fUserBalance, iUTokenSupply, fUTokenSupply sdk.Coins, + iMeTokenBalance, fMeTokenBalance metoken.IndexBalances, + prices metoken.IndexPrices, resp metoken.MsgRedeemResponse, +) { + meTokenDenom, denom := tc.asset.Denom, tc.denom + + // initial state + assetPrice, err := prices.Price(denom) + assert.NilError(t, err) + i, iAssetBalance := iMeTokenBalance.AssetBalance(denom) + assert.Check(t, i >= 0) + assetSupply := iAssetBalance.Leveraged.Add(iAssetBalance.Reserved) + meTokenPrice, err := prices.Price(meTokenDenom) + assert.NilError(t, err) + + assetExponentFactorVsUSD, err := metoken.ExponentFactor(assetPrice.Exponent, 0) + assert.NilError(t, err) + decAssetSupply := assetExponentFactorVsUSD.MulInt(assetSupply) + assetValue := decAssetSupply.Mul(assetPrice.Price) + + meTokenExponentFactor, err := metoken.ExponentFactor(meTokenPrice.Exponent, 0) + assert.NilError(t, err) + decMeTokenSupply := meTokenExponentFactor.MulInt(iMeTokenBalance.MetokenSupply.Amount) + meTokenValue := decMeTokenSupply.Mul(meTokenPrice.Price) + + // current_allocation = asset_value / total_value + // redeem_delta_allocation = (target_allocation - current_allocation) / target_allocation + currentAllocation, redeemDeltaAllocation := sdk.ZeroDec(), sdk.ZeroDec() + i, aa := index.AcceptedAsset(denom) + assert.Check(t, i >= 0) + targetAllocation := aa.TargetAllocation + if assetSupply.IsZero() { + redeemDeltaAllocation = targetAllocation + } else { + currentAllocation = assetValue.Quo(meTokenValue) + redeemDeltaAllocation = targetAllocation.Sub(currentAllocation).Quo(targetAllocation) + } + + // fee = delta_allocation * balanced_fee + balanced_fee + fee := redeemDeltaAllocation.Mul(index.Fee.BalancedFee).Add(index.Fee.BalancedFee) + if fee.LT(index.Fee.MinFee) { + fee = index.Fee.MinFee + } + if fee.GT(index.Fee.MaxFee) { + fee = index.Fee.MaxFee + } + // redeem_exchange_rate = metoken_price / asset_price + redeemExchangeRate := meTokenPrice.Price.Quo(assetPrice.Price) + + assetExponentFactorVsMeToken, err := prices.ExponentFactor(meTokenDenom, denom) + assert.NilError(t, err) + + // amount_to_redeem = exchange_rate * metoken_amount + amountToWithdraw := redeemExchangeRate.MulInt(tc.asset.Amount).Mul(assetExponentFactorVsMeToken).TruncateInt() + + // expected_fee = fee * amount_to_redeem + expectedFee := sdk.NewCoin(denom, fee.MulInt(amountToWithdraw).TruncateInt()) + + // amount_to_redeem = amountToWithdraw - expectedFee + amountToRedeem := amountToWithdraw.Sub(expectedFee.Amount) + + expectedAssets := sdk.NewCoin( + denom, + amountToRedeem, + ) + + // calculating reserved and leveraged + expectedFromReserves := sdk.NewCoin( + denom, + aa.ReservePortion.MulInt(amountToWithdraw).TruncateInt(), + ) + expectedFromLeverage := sdk.NewCoin(denom, amountToWithdraw.Sub(expectedFromReserves.Amount)) + + // verify the outputs of swap function + require.Equal(t, expectedFee, resp.Fee, tc.name, "expectedFee") + require.Equal(t, expectedAssets, resp.Returned, tc.name, "expectedAssets") + + // verify meToken balance decreased and asset balance increased by the expected amounts + require.True( + t, + iUserBalance.Sub(tc.asset).Add(expectedAssets).IsEqual(fUserBalance), + tc.name, + "token balance", + ) + // verify uToken assetSupply decreased by the expected amount + require.True( + t, + iUTokenSupply.Sub( + sdk.NewCoin( + "u/"+expectedFromLeverage.Denom, + expectedFromLeverage.Amount, + ), + ).IsEqual(fUTokenSupply), + tc.name, + "uToken assetSupply", + ) + // from_reserves + from_leverage must be = to total amount withdrawn from the modules + require.True( + t, + expectedFromReserves.Amount.Add(expectedFromLeverage.Amount).Equal(amountToWithdraw), + tc.name, + "total withdraw", + ) + + // meToken assetSupply is decreased by the expected amount + require.True( + t, + iMeTokenBalance.MetokenSupply.Sub(tc.asset).IsEqual(fMeTokenBalance.MetokenSupply), + tc.name, + "meToken assetSupply", + ) + + i, fAssetBalance := fMeTokenBalance.AssetBalance(denom) + assert.Check(t, i >= 0) + require.True( + t, + iAssetBalance.Reserved.Sub(expectedFromReserves.Amount).Equal(fAssetBalance.Reserved), + tc.name, + "reserved", + ) + require.True( + t, + iAssetBalance.Leveraged.Sub(expectedFromLeverage.Amount).Equal(fAssetBalance.Leveraged), + tc.name, + "leveraged", + ) + require.True(t, iAssetBalance.Fees.Add(expectedFee.Amount).Equal(fAssetBalance.Fees), tc.name, "fees") +} + +func TestMsgServer_GovSetParams(t *testing.T) { + s := initKeeperTestSuite(t, nil, nil) + msgServer, ctx, app := s.msgServer, s.ctx, s.app + + testCases := []struct { + name string + req *metoken.MsgGovSetParams + errMsg string + }{ + { + "invalid authority", + metoken.NewMsgGovSetParams("invalid_authority", metoken.Params{}), + "invalid_authority", + }, + { + "valid", + metoken.NewMsgGovSetParams( + app.GovKeeper.GetGovernanceAccount(s.ctx).GetAddress().String(), + metoken.DefaultParams(), + ), + "", + }, + } + + for _, tc := range testCases { + t.Run( + tc.name, func(t *testing.T) { + _, err := msgServer.GovSetParams(ctx, tc.req) + if len(tc.errMsg) > 0 { + assert.ErrorContains(t, err, tc.errMsg) + } else { + assert.NilError(t, err) + } + }, + ) + } +} + +func TestMsgServer_GovUpdateRegistry(t *testing.T) { + s := initKeeperTestSuite(t, nil, nil) + msgServer, ctx, app := s.msgServer, s.ctx, s.app + govAddr := app.GovKeeper.GetGovernanceAccount(s.ctx).GetAddress().String() + + existingIndex := mocks.StableIndex("me/Existing") + _, err := msgServer.GovUpdateRegistry( + ctx, + metoken.NewMsgGovUpdateRegistry(govAddr, []metoken.Index{existingIndex}, nil), + ) + require.NoError(t, err) + + user := s.newAccount( + t, + coin.New(mocks.USDTBaseDenom, 10000_000000), + ) + + // swap 5000 USDT for existing index + swap := &metoken.MsgSwap{ + User: user.String(), + Asset: sdk.NewCoin(mocks.USDTBaseDenom, sdkmath.NewInt(5000_000000)), + MetokenDenom: existingIndex.Denom, + } + + _, err = msgServer.Swap(ctx, swap) + require.NoError(t, err) + existingIndex.Exponent = 10 + + indexWithNotRegisteredToken := metoken.NewIndex( + "me/NotRegistered", + sdk.NewInt(1_000_000_000_000), + 6, + mocks.ValidFee(), + []metoken.AcceptedAsset{ + metoken.NewAcceptedAsset("notRegisteredDenom", sdk.MustNewDecFromStr("0.2"), sdk.MustNewDecFromStr("1.0")), + }, + ) + + deletedAssetIndex := mocks.StableIndex(mocks.MeUSDDenom) + aa := []metoken.AcceptedAsset{ + metoken.NewAcceptedAsset(mocks.USDTBaseDenom, sdk.MustNewDecFromStr("0.2"), sdk.MustNewDecFromStr("0.5")), + metoken.NewAcceptedAsset(mocks.USDCBaseDenom, sdk.MustNewDecFromStr("0.2"), sdk.MustNewDecFromStr("0.5")), + } + deletedAssetIndex.AcceptedAssets = aa + + testCases := []struct { + name string + req *metoken.MsgGovUpdateRegistry + errMsg string + }{ + { + "invalid authority", + metoken.NewMsgGovUpdateRegistry("invalid_authority", nil, nil), + "invalid_authority", + }, + { + "invalid - empty add and update indexes", + metoken.NewMsgGovUpdateRegistry(govAddr, nil, nil), + "empty add and update indexes", + }, + { + "invalid - duplicated add indexes", + metoken.NewMsgGovUpdateRegistry( + govAddr, + []metoken.Index{mocks.StableIndex(mocks.MeUSDDenom), mocks.StableIndex(mocks.MeUSDDenom)}, + nil, + ), + "duplicate addIndex metoken denom", + }, + { + "invalid - duplicated update indexes", + metoken.NewMsgGovUpdateRegistry( + govAddr, + []metoken.Index{mocks.StableIndex(mocks.MeUSDDenom)}, + []metoken.Index{mocks.StableIndex(mocks.MeUSDDenom)}, + ), + "duplicate updateIndex metoken denom", + }, + { + "invalid - add index", + metoken.NewMsgGovUpdateRegistry( + govAddr, + []metoken.Index{mocks.StableIndex(mocks.USDTBaseDenom)}, + nil, + ), + "should have the following format: me/", + }, + { + "invalid - existing add index", + metoken.NewMsgGovUpdateRegistry(govAddr, []metoken.Index{existingIndex}, nil), + "already exists", + }, + { + "invalid - index with not registered token", + metoken.NewMsgGovUpdateRegistry(govAddr, []metoken.Index{indexWithNotRegisteredToken}, nil), + "not a registered Token", + }, + { + "valid - add", + metoken.NewMsgGovUpdateRegistry(govAddr, []metoken.Index{mocks.StableIndex(mocks.MeUSDDenom)}, nil), + "", + }, + { + "invalid - update index", + metoken.NewMsgGovUpdateRegistry( + govAddr, + nil, + []metoken.Index{mocks.StableIndex(mocks.USDTBaseDenom)}, + ), + "should have the following format: me/", + }, + { + "invalid - non-existing update index", + metoken.NewMsgGovUpdateRegistry(govAddr, nil, []metoken.Index{mocks.StableIndex("me/NonExisting")}), + "not found", + }, + { + "invalid - update index exponent with balance", + metoken.NewMsgGovUpdateRegistry(govAddr, nil, []metoken.Index{existingIndex}), + "exponent cannot be changed when supply is greater than zero", + }, + { + "invalid - update index deleting an asset", + metoken.NewMsgGovUpdateRegistry(govAddr, nil, []metoken.Index{deletedAssetIndex}), + "cannot be deleted from an index", + }, + } + + for _, tc := range testCases { + t.Run( + tc.name, func(t *testing.T) { + _, err := msgServer.GovUpdateRegistry(ctx, tc.req) + if len(tc.errMsg) > 0 { + assert.ErrorContains(t, err, tc.errMsg) + } else { + assert.NilError(t, err) + for _, addIndex := range tc.req.AddIndex { + index, err := app.MetokenKeeperB.Keeper(&ctx).RegisteredIndex( + addIndex.Denom, + ) + require.NoError(t, err) + assert.DeepEqual(t, addIndex, index) + + balances, found := app.MetokenKeeperB.Keeper(&ctx).IndexBalances( + addIndex.Denom, + ) + assert.Check(t, found) + for _, aa := range addIndex.AcceptedAssets { + i, balance := balances.AssetBalance(aa.Denom) + assert.Check(t, i >= 0) + assert.Check(t, balance.Fees.Equal(sdkmath.ZeroInt())) + assert.Check(t, balance.Interest.Equal(sdkmath.ZeroInt())) + assert.Check(t, balance.Leveraged.Equal(sdkmath.ZeroInt())) + assert.Check(t, balance.Reserved.Equal(sdkmath.ZeroInt())) + } + } + + for _, updateIndex := range tc.req.AddIndex { + index, err := app.MetokenKeeperB.Keeper(&ctx).RegisteredIndex(updateIndex.Denom) + require.NoError(t, err) + assert.DeepEqual(t, updateIndex, index) + + balances, found := app.MetokenKeeperB.Keeper(&ctx).IndexBalances(updateIndex.Denom) + assert.Check(t, found) + for _, aa := range updateIndex.AcceptedAssets { + i, balance := balances.AssetBalance(aa.Denom) + assert.Check(t, i >= 0) + assert.Check(t, balance.Fees.Equal(sdkmath.ZeroInt())) + assert.Check(t, balance.Interest.Equal(sdkmath.ZeroInt())) + assert.Check(t, balance.Leveraged.Equal(sdkmath.ZeroInt())) + assert.Check(t, balance.Reserved.Equal(sdkmath.ZeroInt())) + } + } + } + }, + ) + } +} diff --git a/x/metoken/keeper/keeper.go b/x/metoken/keeper/keeper.go new file mode 100644 index 0000000000..bc1687dc40 --- /dev/null +++ b/x/metoken/keeper/keeper.go @@ -0,0 +1,64 @@ +package keeper + +import ( + "github.com/cosmos/cosmos-sdk/codec" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/tendermint/tendermint/libs/log" + + "github.com/umee-network/umee/v5/x/metoken" +) + +// Builder constructs Keeper by preparing all related dependencies (notably the store). +type Builder struct { + cdc codec.Codec + storeKey storetypes.StoreKey + bankKeeper metoken.BankKeeper + leverageKeeper metoken.LeverageKeeper + oracleKeeper metoken.OracleKeeper +} + +// NewKeeperBuilder returns Builder object. +func NewKeeperBuilder( + cdc codec.Codec, + storeKey storetypes.StoreKey, + bankKeeper metoken.BankKeeper, + leverageKeeper metoken.LeverageKeeper, + oracleKeeper metoken.OracleKeeper, +) Builder { + return Builder{ + cdc: cdc, + storeKey: storeKey, + bankKeeper: bankKeeper, + leverageKeeper: leverageKeeper, + oracleKeeper: oracleKeeper, + } +} + +type Keeper struct { + cdc codec.Codec + store sdk.KVStore + bankKeeper metoken.BankKeeper + leverageKeeper metoken.LeverageKeeper + oracleKeeper metoken.OracleKeeper + + // TODO: ctx should be removed when we migrate leverageKeeper and oracleKeeper + ctx *sdk.Context +} + +// Keeper creates a new Keeper object +func (b Builder) Keeper(ctx *sdk.Context) Keeper { + return Keeper{ + cdc: b.cdc, + store: ctx.KVStore(b.storeKey), + bankKeeper: b.bankKeeper, + leverageKeeper: b.leverageKeeper, + oracleKeeper: b.oracleKeeper, + ctx: ctx, + } +} + +// Logger returns module Logger +func (k Keeper) Logger() log.Logger { + return k.ctx.Logger().With("module", "x/"+metoken.ModuleName) +} diff --git a/x/metoken/keeper/keys.go b/x/metoken/keeper/keys.go new file mode 100644 index 0000000000..ed71218d6c --- /dev/null +++ b/x/metoken/keeper/keys.go @@ -0,0 +1,25 @@ +package keeper + +import "github.com/umee-network/umee/v5/util" + +var ( + // Regular state + keyPrefixIndex = []byte{0x01} + keyPrefixBalances = []byte{0x02} + keyPrefixNextRebalancingTime = []byte{0x03} + keyPrefixNextInterestClaimTime = []byte{0x04} + // keyPrefixParams is the key to query all gov params + keyPrefixParams = []byte{0x05} +) + +// keyIndex returns a KVStore key for index parameters for specific Index. +func keyIndex(meTokendenom string) []byte { + // keyPrefixIndex | meTokendenom + return util.ConcatBytes(0, keyPrefixIndex, []byte(meTokendenom)) +} + +// keyBalance returns a KVStore key for balance of a specific Index. +func keyBalance(meTokendenom string) []byte { + // keyPrefixBalances | meTokendenom + return util.ConcatBytes(0, keyPrefixBalances, []byte(meTokendenom)) +} diff --git a/x/metoken/keeper/metoken.go b/x/metoken/keeper/metoken.go new file mode 100644 index 0000000000..e99ae6a1fa --- /dev/null +++ b/x/metoken/keeper/metoken.go @@ -0,0 +1,205 @@ +package keeper + +import ( + "time" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + "github.com/umee-network/umee/v5/util/store" + "github.com/umee-network/umee/v5/x/metoken" +) + +// GetAllRegisteredIndexes returns all the registered Indexes from the x/metoken +// module's KVStore. +func (k Keeper) GetAllRegisteredIndexes() []metoken.Index { + return store.MustLoadAll[*metoken.Index](k.store, keyPrefixIndex) +} + +// RegisteredIndex gets an Index from the x/metoken module's KVStore, if not found returns an error. +func (k Keeper) RegisteredIndex(meTokenDenom string) (metoken.Index, error) { + index := store.GetValue[*metoken.Index](k.store, keyIndex(meTokenDenom), "index") + + if index == nil { + return metoken.Index{}, sdkerrors.ErrNotFound.Wrapf("index %s not found", meTokenDenom) + } + + return *index, nil +} + +// setRegisteredIndex saves a meToken Index with accepted assets and parameters +func (k Keeper) setRegisteredIndex(index metoken.Index) error { + if err := index.Validate(); err != nil { + return err + } + + return store.SetValue(k.store, keyIndex(index.Denom), &index, "index") +} + +// GetAllIndexesBalances returns asset balances of every Index +func (k Keeper) GetAllIndexesBalances() []metoken.IndexBalances { + return store.MustLoadAll[*metoken.IndexBalances](k.store, keyPrefixBalances) +} + +// getNextRebalancingTime returns next x/metoken re-balancing time in Milliseconds. +func (k Keeper) getNextRebalancingTime() (time.Time, error) { + return store.GetTimeMs(k.store, keyPrefixNextRebalancingTime) +} + +// setNextRebalancingTime next x/metoken re-balancing time in Milliseconds. +func (k Keeper) setNextRebalancingTime(nextRebalancingTime time.Time) { + store.SetTimeMs(k.store, keyPrefixNextRebalancingTime, nextRebalancingTime) +} + +// getNextInterestClaimTime returns next x/metoken interest claiming time in Milliseconds. +func (k Keeper) getNextInterestClaimTime() (time.Time, error) { + return store.GetTimeMs(k.store, keyPrefixNextInterestClaimTime) +} + +// setNextInterestClaimTime next x/metoken interest claiming time in Milliseconds. +func (k Keeper) setNextInterestClaimTime(nextInterestClaimTime time.Time) { + store.SetTimeMs(k.store, keyPrefixNextInterestClaimTime, nextInterestClaimTime) +} + +// UpdateIndexes registers `addIndexes` and processes `updateIndexes` to update existing indexes. +func (k Keeper) UpdateIndexes( + addIndexes []metoken.Index, + updateIndexes []metoken.Index, +) error { + registry := k.GetAllRegisteredIndexes() + + registeredIndexes := make(map[string]metoken.Index) + for _, index := range registry { + registeredIndexes[index.Denom] = index + } + + if err := k.addIndexes(addIndexes, registeredIndexes); err != nil { + return err + } + + return k.updateIndexes(updateIndexes, registeredIndexes) +} + +// addIndexes handles addition of the indexes from the request along with their validations. +func (k Keeper) addIndexes(indexes []metoken.Index, registeredIndexes map[string]metoken.Index) error { + for _, index := range indexes { + if _, present := registeredIndexes[index.Denom]; present { + return sdkerrors.ErrInvalidRequest.Wrapf( + "add: index with denom %s already exists", + index.Denom, + ) + } + + if err := k.validateInLeverage(index); err != nil { + return err + } + + if exists := k.hasIndexBalance(index.Denom); exists { + return sdkerrors.ErrInvalidRequest.Wrapf( + "can't add index %s - it already exists and is active", + index.Denom, + ) + } + + // adding index + if err := k.setRegisteredIndex(index); err != nil { + return err + } + + assetBalances := make([]metoken.AssetBalance, 0) + for _, aa := range index.AcceptedAssets { + assetBalances = append(assetBalances, metoken.NewZeroAssetBalance(aa.Denom)) + } + + // adding initial balances for the index + if err := k.setIndexBalances( + metoken.NewIndexBalances( + sdk.NewCoin( + index.Denom, + sdkmath.ZeroInt(), + ), assetBalances, + ), + ); err != nil { + return err + } + } + + return nil +} + +// updateIndexes handles updates of the indexes from the request along with their validations. +func (k Keeper) updateIndexes(indexes []metoken.Index, registeredIndexes map[string]metoken.Index) error { + for _, index := range indexes { + oldIndex, present := registeredIndexes[index.Denom] + if !present { + return sdkerrors.ErrNotFound.Wrapf( + "update: index with denom %s not found", + index.Denom, + ) + } + + if oldIndex.Exponent != index.Exponent { + balances, err := k.IndexBalances(index.Denom) + if err != nil { + return err + } + + if balances.MetokenSupply.IsPositive() { + return sdkerrors.ErrInvalidRequest.Wrapf( + "update: index %s exponent cannot be changed when supply is greater than zero", + index.Denom, + ) + } + } + + for _, aa := range oldIndex.AcceptedAssets { + if exists := index.HasAcceptedAsset(aa.Denom); !exists { + return sdkerrors.ErrInvalidRequest.Wrapf( + "update: an asset %s cannot be deleted from an index %s", + aa.Denom, + index.Denom, + ) + } + } + + if err := k.validateInLeverage(index); err != nil { + return err + } + + // updating balances if there is a new accepted asset + if len(index.AcceptedAssets) > len(oldIndex.AcceptedAssets) { + balances, err := k.IndexBalances(index.Denom) + if err != nil { + return err + } + + for _, aa := range index.AcceptedAssets { + if i, _ := balances.AssetBalance(aa.Denom); i < 0 { + balances.AssetBalances = append(balances.AssetBalances, metoken.NewZeroAssetBalance(aa.Denom)) + } + } + + if err := k.setIndexBalances(balances); err != nil { + return err + } + } + + if err := k.setRegisteredIndex(index); err != nil { + return err + } + } + + return nil +} + +// validateInLeverage validate the existence of every accepted asset in x/leverage +func (k Keeper) validateInLeverage(index metoken.Index) error { + for _, aa := range index.AcceptedAssets { + if _, err := k.leverageKeeper.GetTokenSettings(*k.ctx, aa.Denom); err != nil { + return err + } + } + + return nil +} diff --git a/x/metoken/keeper/metoken_test.go b/x/metoken/keeper/metoken_test.go new file mode 100644 index 0000000000..edf8b923ed --- /dev/null +++ b/x/metoken/keeper/metoken_test.go @@ -0,0 +1,119 @@ +package keeper + +import ( + "testing" + + sdkmath "cosmossdk.io/math" + + "github.com/stretchr/testify/require" + "gotest.tools/v3/assert" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/umee-network/umee/v5/x/leverage/types" + "github.com/umee-network/umee/v5/x/metoken" + "github.com/umee-network/umee/v5/x/metoken/mocks" +) + +func TestIndex_AddAndUpdate(t *testing.T) { + l := NewLeverageMock() + k := initMeUSDKeeper(t, nil, l, nil) + index, err := k.RegisteredIndex(mocks.MeUSDDenom) + require.NoError(t, err) + + indexWithNotRegisteredAsset := metoken.NewIndex( + "", sdkmath.ZeroInt(), 6, metoken.Fee{}, + []metoken.AcceptedAsset{ + metoken.NewAcceptedAsset( + "test", sdk.MustNewDecFromStr("0.2"), + sdk.MustNewDecFromStr("1.0"), + ), + }, + ) + + invalid := metoken.NewIndex( + "", sdkmath.ZeroInt(), 6, metoken.Fee{}, + []metoken.AcceptedAsset{ + metoken.NewAcceptedAsset( + mocks.USDTBaseDenom, sdk.MustNewDecFromStr("0.2"), + sdk.MustNewDecFromStr("1.0"), + ), + }, + ) + + changedExponent := mocks.StableIndex(mocks.MeUSDDenom) + changedExponent.Exponent = 10 + + deletedAsset := mocks.StableIndex(mocks.MeUSDDenom) + deletedAsset.AcceptedAssets = deletedAsset.AcceptedAssets[:1] + + tcs := []struct { + name string + addIndex []metoken.Index + updateIndex []metoken.Index + errMsg string + }{ + { + name: "add: duplicated index", + addIndex: []metoken.Index{index}, + updateIndex: nil, + errMsg: "already exists", + }, + { + name: "add: asset not registered in x/leverage", + addIndex: []metoken.Index{indexWithNotRegisteredAsset}, + updateIndex: nil, + errMsg: types.ErrNotRegisteredToken.Error(), + }, + { + name: "add: index don't pass validation", + addIndex: []metoken.Index{invalid}, + updateIndex: nil, + errMsg: "should have the following format", + }, + { + name: "add: valid", + addIndex: []metoken.Index{mocks.StableIndex("me/TH")}, + updateIndex: nil, + errMsg: "", + }, + { + name: "update: index not found", + addIndex: nil, + updateIndex: []metoken.Index{mocks.StableIndex("me/NotFound")}, + errMsg: "not found", + }, + { + name: "update: changed exponent after minting meTokens", + addIndex: nil, + updateIndex: []metoken.Index{changedExponent}, + errMsg: "exponent cannot be changed when supply is greater than zero", + }, + { + name: "update: deleted asset", + addIndex: nil, + updateIndex: []metoken.Index{deletedAsset}, + errMsg: "cannot be deleted from an index", + }, + { + name: "update: valid", + addIndex: nil, + updateIndex: []metoken.Index{mocks.StableIndex(mocks.MeUSDDenom)}, + errMsg: "", + }, + } + + for _, tc := range tcs { + t.Run( + tc.name, func(t *testing.T) { + err := k.UpdateIndexes(tc.addIndex, tc.updateIndex) + if tc.errMsg != "" { + assert.ErrorContains(t, err, tc.errMsg) + } else { + assert.NilError(t, err) + } + }, + ) + } + +} diff --git a/x/metoken/keeper/mocks_test.go b/x/metoken/keeper/mocks_test.go new file mode 100644 index 0000000000..e4833b1983 --- /dev/null +++ b/x/metoken/keeper/mocks_test.go @@ -0,0 +1,68 @@ +package keeper + +import ( + sdkmath "cosmossdk.io/math" + "github.com/umee-network/umee/v5/x/metoken/mocks" + + sdk "github.com/cosmos/cosmos-sdk/types" + ltypes "github.com/umee-network/umee/v5/x/leverage/types" + otypes "github.com/umee-network/umee/v5/x/oracle/types" +) + +type Oracle struct { + prices otypes.Prices +} + +func (o Oracle) AllMedianPrices(_ sdk.Context) otypes.Prices { + return o.prices +} + +func NewOracleMock() Oracle { + return Oracle{prices: mocks.ValidPrices()} +} + +type Leverage struct { + tokens map[string]ltypes.Token +} + +func (l Leverage) GetTokenSettings(_ sdk.Context, denom string) (ltypes.Token, error) { + ts, ok := l.tokens[denom] + if !ok { + return ts, ltypes.ErrNotRegisteredToken.Wrap(denom) + } + return ts, nil +} + +func (l Leverage) ExchangeToken(_ sdk.Context, _ sdk.Coin) (sdk.Coin, error) { + panic("not implemented") +} + +func (l Leverage) ExchangeUToken(_ sdk.Context, _ sdk.Coin) (sdk.Coin, error) { + panic("not implemented") +} + +func (l Leverage) Supply(_ sdk.Context, _ sdk.AccAddress, _ sdk.Coin) (sdk.Coin, error) { + panic("not implemented") +} + +func (l Leverage) Withdraw(_ sdk.Context, _ sdk.AccAddress, _ sdk.Coin) (sdk.Coin, bool, error) { + panic("not implemented") +} + +func (l Leverage) ModuleMaxWithdraw(_ sdk.Context, _ sdk.Coin) (sdkmath.Int, error) { + panic("not implemented") +} + +func (l Leverage) GetTotalSupply(_ sdk.Context, _ string) (sdk.Coin, error) { + panic("not implemented") +} + +func NewLeverageMock() Leverage { + return Leverage{ + tokens: map[string]ltypes.Token{ + mocks.USDTBaseDenom: mocks.ValidToken(mocks.USDTBaseDenom, mocks.USDTSymbolDenom, 6), + mocks.USDCBaseDenom: mocks.ValidToken(mocks.USDCBaseDenom, mocks.USDCSymbolDenom, 6), + mocks.ISTBaseDenom: mocks.ValidToken(mocks.ISTBaseDenom, mocks.ISTSymbolDenom, 6), + }, + } +} diff --git a/x/metoken/keeper/msg_server.go b/x/metoken/keeper/msg_server.go new file mode 100644 index 0000000000..a46a67d001 --- /dev/null +++ b/x/metoken/keeper/msg_server.go @@ -0,0 +1,147 @@ +package keeper + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/umee-network/umee/v5/util/sdkutil" + + "github.com/umee-network/umee/v5/x/metoken" +) + +var _ metoken.MsgServer = msgServer{} + +type msgServer struct { + kb Builder +} + +// NewMsgServerImpl returns an implementation of MsgServer for the x/metoken +// module. +func NewMsgServerImpl(kb Builder) metoken.MsgServer { + return &msgServer{kb: kb} +} + +// Swap handles the request for the swap, delegates the execution and returns the response. +func (m msgServer) Swap(goCtx context.Context, msg *metoken.MsgSwap) (*metoken.MsgSwapResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + k := m.kb.Keeper(&ctx) + + if err := msg.ValidateBasic(); err != nil { + return nil, err + } + + userAddr, err := sdk.AccAddressFromBech32(msg.User) + if err != nil { + return nil, err + } + + resp, err := k.swap(userAddr, msg.MetokenDenom, msg.Asset) + if err != nil { + return nil, err + } + + k.Logger().Debug( + "swap executed", + "user", userAddr, + "meTokens", resp.meTokens.String(), + "calculateFee", resp.fee.String(), + "reserved", resp.reserved.String(), + "leveraged", resp.leveraged.String(), + ) + + sdkutil.Emit( + &ctx, &metoken.EventSwap{ + Recipient: msg.User, + Asset: sdk.NewCoin(msg.Asset.Denom, resp.reserved.Amount.Add(resp.leveraged.Amount)), + Metoken: resp.meTokens, + Fee: resp.fee, + }, + ) + + return &metoken.MsgSwapResponse{ + Fee: resp.fee, + Returned: resp.meTokens, + }, nil +} + +// Redeem handles the request for the redemption, delegates the execution and returns the response. +func (m msgServer) Redeem(goCtx context.Context, msg *metoken.MsgRedeem) (*metoken.MsgRedeemResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + k := m.kb.Keeper(&ctx) + + if err := msg.ValidateBasic(); err != nil { + return nil, err + } + + userAddr, err := sdk.AccAddressFromBech32(msg.User) + if err != nil { + return nil, err + } + + resp, err := k.redeem(userAddr, msg.Metoken, msg.AssetDenom) + if err != nil { + return nil, err + } + + k.Logger().Debug( + "redeem executed", + "user", userAddr, + "calculateFee", resp.fee.String(), + "from_reserves", resp.fromReserves.String(), + "from_leverage", resp.fromLeverage.String(), + "burned", msg.Metoken.String(), + ) + + totalRedeemed := sdk.NewCoin( + msg.AssetDenom, + resp.fromReserves.Amount.Add(resp.fromLeverage.Amount).Sub(resp.fee.Amount), + ) + sdkutil.Emit( + &ctx, &metoken.EventRedeem{ + Recipient: msg.User, + Metoken: msg.Metoken, + Asset: totalRedeemed, + Fee: resp.fee, + }, + ) + + return &metoken.MsgRedeemResponse{ + Returned: totalRedeemed, + Fee: resp.fee, + }, nil +} + +// GovSetParams handles the request for updating Params. +func (m msgServer) GovSetParams(goCtx context.Context, msg *metoken.MsgGovSetParams) ( + *metoken.MsgGovSetParamsResponse, + error, +) { + ctx := sdk.UnwrapSDKContext(goCtx) + if err := msg.ValidateBasic(); err != nil { + return nil, err + } + + if err := m.kb.Keeper(&ctx).SetParams(msg.Params); err != nil { + return nil, err + } + + return &metoken.MsgGovSetParamsResponse{}, nil +} + +// GovUpdateRegistry handles the request for updating the indexes' registry. +func (m msgServer) GovUpdateRegistry( + goCtx context.Context, + msg *metoken.MsgGovUpdateRegistry, +) (*metoken.MsgGovUpdateRegistryResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + if err := msg.ValidateBasic(); err != nil { + return nil, err + } + + if err := m.kb.Keeper(&ctx).UpdateIndexes(msg.AddIndex, msg.UpdateIndex); err != nil { + return nil, err + } + + return &metoken.MsgGovUpdateRegistryResponse{}, nil +} diff --git a/x/metoken/keeper/params.go b/x/metoken/keeper/params.go new file mode 100644 index 0000000000..7821bba077 --- /dev/null +++ b/x/metoken/keeper/params.go @@ -0,0 +1,23 @@ +package keeper + +import ( + "github.com/umee-network/umee/v5/util/store" + + "github.com/umee-network/umee/v5/x/metoken" +) + +// SetParams sets the x/metoken module's parameters. +func (k Keeper) SetParams(params metoken.Params) error { + return store.SetValue(k.store, keyPrefixParams, ¶ms, "params") +} + +// GetParams gets the x/metoken module's parameters. +func (k Keeper) GetParams() metoken.Params { + params := store.GetValue[*metoken.Params](k.store, keyPrefixParams, "params") + + if params == nil { + return metoken.Params{} + } + + return *params +} diff --git a/x/metoken/keeper/params_test.go b/x/metoken/keeper/params_test.go new file mode 100644 index 0000000000..af469e735a --- /dev/null +++ b/x/metoken/keeper/params_test.go @@ -0,0 +1,20 @@ +package keeper + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/umee-network/umee/v5/x/metoken" +) + +func TestUnitParams(t *testing.T) { + k := initSimpleKeeper(t) + params := metoken.DefaultParams() + + err := k.SetParams(params) + require.NoError(t, err) + + params2 := k.GetParams() + require.Equal(t, params, params2) +} diff --git a/x/metoken/keeper/price.go b/x/metoken/keeper/price.go new file mode 100644 index 0000000000..34a6a460cc --- /dev/null +++ b/x/metoken/keeper/price.go @@ -0,0 +1,110 @@ +package keeper + +import ( + "fmt" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + "github.com/umee-network/umee/v5/x/metoken" + otypes "github.com/umee-network/umee/v5/x/oracle/types" +) + +var ( + usdExponent = uint32(0) +) + +// Prices calculates meToken price as an avg of median prices of all index accepted assets. +func (k Keeper) Prices(index metoken.Index) (metoken.IndexPrices, error) { + indexPrices := metoken.NewIndexPrices() + meTokenDenom := index.Denom + + supply, err := k.IndexBalances(index.Denom) + if err != nil { + return indexPrices, err + } + + allPrices := k.oracleKeeper.AllMedianPrices(*k.ctx) + + // calculate the total assets value in the index balances + totalAssetsUSDValue := sdk.ZeroDec() + for _, aa := range index.AcceptedAssets { + // get token settings from leverageKeeper to use the symbol_denom + tokenSettings, err := k.leverageKeeper.GetTokenSettings(*k.ctx, aa.Denom) + if err != nil { + return indexPrices, err + } + + assetPrice, err := latestPrice(allPrices, tokenSettings.SymbolDenom) + if err != nil { + return indexPrices, err + } + indexPrices.SetPrice(aa.Denom, assetPrice, tokenSettings.Exponent) + + // if no meTokens were minted, the totalAssetValue is the sum of all the assets prices. + // otherwise is the sum of the value of all the assets in the index. + if supply.MetokenSupply.IsZero() { + totalAssetsUSDValue = totalAssetsUSDValue.Add(assetPrice) + } else { + i, balance := supply.AssetBalance(aa.Denom) + if i < 0 { + return indexPrices, sdkerrors.ErrNotFound.Wrapf("balance for denom %s not found", aa.Denom) + } + + assetUSDValue, err := valueInUSD(balance.AvailableSupply(), assetPrice, tokenSettings.Exponent) + if err != nil { + return indexPrices, err + } + totalAssetsUSDValue = totalAssetsUSDValue.Add(assetUSDValue) + } + } + + if supply.MetokenSupply.IsZero() { + // if no meTokens were minted, the meTokenPrice is totalAssetsUSDValue divided by accepted assets quantity + indexPrices.SetPrice( + meTokenDenom, + totalAssetsUSDValue.QuoInt(sdkmath.NewInt(int64(len(index.AcceptedAssets)))), + index.Exponent, + ) + } else { + // otherwise, the meTokenPrice is totalAssetsUSDValue divided by meTokens minted quantity + meTokenPrice, err := priceInUSD(supply.MetokenSupply.Amount, totalAssetsUSDValue, index.Exponent) + if err != nil { + return indexPrices, err + } + indexPrices.SetPrice(meTokenDenom, meTokenPrice, index.Exponent) + } + + return indexPrices, nil +} + +// latestPrice from the list of medians, based on the block number. +func latestPrice(prices otypes.Prices, symbolDenom string) (sdk.Dec, error) { + denomPrices := prices.FilterByDenom(symbolDenom) + + if len(denomPrices) == 0 { + return sdk.Dec{}, fmt.Errorf("price not found in oracle for denom %s", symbolDenom) + } + + return denomPrices[len(denomPrices)-1].ExchangeRateTuple.ExchangeRate, nil +} + +// valueInUSD given a specific amount, price and exponent +func valueInUSD(amount sdkmath.Int, assetPrice sdk.Dec, assetExponent uint32) (sdk.Dec, error) { + exponentFactor, err := metoken.ExponentFactor(assetExponent, usdExponent) + if err != nil { + return sdk.Dec{}, err + } + return exponentFactor.MulInt(amount).Mul(assetPrice), nil +} + +// priceInUSD given a specific amount, totalValue and exponent +func priceInUSD(amount sdkmath.Int, totalValue sdk.Dec, assetExponent uint32) (sdk.Dec, error) { + exponentFactor, err := metoken.ExponentFactor(assetExponent, usdExponent) + if err != nil { + return sdk.Dec{}, err + } + + return totalValue.Quo(exponentFactor.MulInt(amount)), nil +} diff --git a/x/metoken/keeper/price_test.go b/x/metoken/keeper/price_test.go new file mode 100644 index 0000000000..08373b711c --- /dev/null +++ b/x/metoken/keeper/price_test.go @@ -0,0 +1,189 @@ +package keeper + +import ( + "testing" + + "github.com/umee-network/umee/v5/x/metoken/mocks" + + sdkmath "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/stretchr/testify/require" + + "github.com/umee-network/umee/v5/x/metoken" +) + +func TestIndexPrices_Prices(t *testing.T) { + o := NewOracleMock() + l := NewLeverageMock() + k := initMeUSDKeeper(t, nil, l, o) + index, err := k.RegisteredIndex(mocks.MeUSDDenom) + require.NoError(t, err) + + // inexisting asset case + ip, err := k.Prices(index) + require.NoError(t, err) + _, err = ip.Price("inexistingAsset") + require.ErrorContains(t, err, "not found") + + // confirm all the asset prices are set correctly + price, err := ip.Price(mocks.USDTBaseDenom) + require.NoError(t, err) + require.Equal(t, price.Exponent, uint32(6)) + require.True(t, price.Price.Equal(mocks.USDTPrice)) + + price, err = ip.Price(mocks.USDCBaseDenom) + require.NoError(t, err) + require.Equal(t, price.Exponent, uint32(6)) + require.True(t, price.Price.Equal(mocks.USDCPrice)) + + price, err = ip.Price(mocks.ISTBaseDenom) + require.NoError(t, err) + require.Equal(t, price.Exponent, uint32(6)) + require.True(t, price.Price.Equal(mocks.ISTPrice)) + + // case with 4960 meTokens minted + // metoken_price = (supply1 * price1 + supply2 * price2 + supplyN * priceN) / metokens_minted + // metoken_price = (1200 * 0.998 + 760 * 1.0 + 3000 * 1.02) / 4960 = 1.011612903225806452 + price, err = ip.Price(mocks.MeUSDDenom) + require.NoError(t, err) + require.Equal(t, price.Exponent, uint32(6)) + require.True(t, price.Price.Equal(sdk.MustNewDecFromStr("1.011612903225806452"))) + + // case with no meTokens minted + balance := mocks.EmptyUSDIndexBalances(mocks.MeUSDDenom) + err = k.setIndexBalances(balance) + require.NoError(t, err) + + // case with 0 meTokens minted + // metoken_price = (price1 + price2 + priceN) / N + // metoken_price = (0.998 + 1.0 + 1.02) / 3 = 1.006 + ip, err = k.Prices(index) + require.NoError(t, err) + price, err = ip.Price(mocks.MeUSDDenom) + require.NoError(t, err) + require.Equal(t, price.Exponent, uint32(6)) + require.True(t, price.Price.Equal(sdk.MustNewDecFromStr("1.006"))) +} + +func TestIndexPrices_Convert(t *testing.T) { + o := NewOracleMock() + l := NewLeverageMock() + k := initMeUSDKeeper(t, nil, l, o) + + // same exponent cases + index, err := k.RegisteredIndex(mocks.MeUSDDenom) + require.NoError(t, err) + ip, err := k.Prices(index) + require.NoError(t, err) + + meTokenPrice, err := ip.Price(mocks.MeUSDDenom) + require.NoError(t, err) + + // convert 20 USDC to meUSD + usdcPrice, err := ip.Price(mocks.USDCBaseDenom) + require.NoError(t, err) + + coin := sdk.NewCoin(mocks.USDCBaseDenom, sdkmath.NewInt(20_000000)) + result, err := ip.SwapRate(coin, mocks.MeUSDDenom) + require.NoError(t, err) + require.True(t, result.Equal(usdcPrice.Price.Quo(meTokenPrice.Price).MulInt(coin.Amount).TruncateInt())) + + // convert 130 meUSD to IST + istPrice, err := ip.Price(mocks.ISTBaseDenom) + require.NoError(t, err) + + coin = sdk.NewCoin(mocks.MeUSDDenom, sdkmath.NewInt(130_000000)) + result, err = ip.SwapRate(coin, mocks.ISTBaseDenom) + require.NoError(t, err) + require.True(t, result.Equal(meTokenPrice.Price.Quo(istPrice.Price).MulInt(coin.Amount).TruncateInt())) + + // diff exponent cases + // change exponents in leverage + usdtSettings := l.tokens[mocks.USDCBaseDenom] + usdtSettings.Exponent = 8 + l.tokens[mocks.USDCBaseDenom] = usdtSettings + istSettings := l.tokens[mocks.ISTBaseDenom] + istSettings.Exponent = 4 + l.tokens[mocks.ISTBaseDenom] = istSettings + + // change supply given the new exponents + supply, err := k.IndexBalances(mocks.MeUSDDenom) + require.NoError(t, err) + i, usdtBalance := supply.AssetBalance(mocks.USDCBaseDenom) + require.True(t, i >= 0) + usdtBalance.Reserved = usdtBalance.Reserved.Mul(sdkmath.NewInt(100)) + usdtBalance.Leveraged = usdtBalance.Leveraged.Mul(sdkmath.NewInt(100)) + supply.SetAssetBalance(usdtBalance) + + i, istBalance := supply.AssetBalance(mocks.ISTBaseDenom) + require.True(t, i >= 0) + istBalance.Reserved = istBalance.Reserved.Quo(sdkmath.NewInt(100)) + istBalance.Leveraged = istBalance.Leveraged.Quo(sdkmath.NewInt(100)) + supply.SetAssetBalance(istBalance) + + err = k.setIndexBalances(supply) + + ip, err = k.Prices(index) + require.NoError(t, err) + + // convert 115 USDC to meUSD + usdcPrice, err = ip.Price(mocks.USDCBaseDenom) + require.NoError(t, err) + + coin = sdk.NewCoin(mocks.USDCBaseDenom, sdkmath.NewInt(115_000000)) + result, err = ip.SwapRate(coin, mocks.MeUSDDenom) + require.NoError(t, err) + require.True( + t, result.Equal( + usdcPrice.Price.Quo(meTokenPrice.Price).MulInt(coin.Amount).Mul( + sdk. + MustNewDecFromStr("0.01"), + ).TruncateInt(), + ), + ) + + // convert 1783.91827311 meUSD to IST + istPrice, err = ip.Price(mocks.ISTBaseDenom) + require.NoError(t, err) + + coin = sdk.NewCoin(mocks.MeUSDDenom, sdkmath.NewInt(1783_91827311)) + result, err = ip.SwapRate(coin, mocks.ISTBaseDenom) + require.NoError(t, err) + require.True( + t, result.Equal( + meTokenPrice.Price.Quo(istPrice.Price).MulInt(coin.Amount).QuoInt( + sdkmath.NewInt( + 100, + ), + ).TruncateInt(), + ), + ) +} + +func meUSDIndexPricesAdjustedToBalance(t *testing.T, balance metoken.IndexBalances) metoken.IndexPrices { + i, usdtSupply := balance.AssetBalance(mocks.USDTBaseDenom) + require.True(t, i >= 0) + i, usdcSupply := balance.AssetBalance(mocks.USDCBaseDenom) + require.True(t, i >= 0) + i, istSupply := balance.AssetBalance(mocks.ISTBaseDenom) + require.True(t, i >= 0) + + prices := metoken.NewIndexPrices() + prices.SetPrice(mocks.USDTBaseDenom, mocks.USDTPrice, 6) + prices.SetPrice(mocks.USDCBaseDenom, mocks.USDCPrice, 6) + prices.SetPrice(mocks.ISTBaseDenom, mocks.ISTPrice, 6) + prices.SetPrice( + mocks.MeUSDDenom, + mocks.USDTPrice.MulInt(usdtSupply.AvailableSupply()).Add( + mocks.USDCPrice.MulInt( + usdcSupply. + AvailableSupply(), + ), + ).Add(mocks.ISTPrice.MulInt(istSupply.AvailableSupply())).QuoInt(balance.MetokenSupply.Amount), + 6, + ) + + return prices +} diff --git a/x/metoken/keeper/redeem.go b/x/metoken/keeper/redeem.go new file mode 100644 index 0000000000..c2732d016c --- /dev/null +++ b/x/metoken/keeper/redeem.go @@ -0,0 +1,207 @@ +package keeper + +import ( + "fmt" + + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/umee-network/umee/v5/x/metoken" +) + +// redeemResponse wraps all the coins of a successful redemption +type redeemResponse struct { + fee sdk.Coin + fromReserves sdk.Coin + fromLeverage sdk.Coin +} + +func newRedeemResponse(fee sdk.Coin, fromReserves sdk.Coin, fromLeverage sdk.Coin) redeemResponse { + return redeemResponse{ + fee: fee, + fromReserves: fromReserves, + fromLeverage: fromLeverage, + } +} + +// redeem executes all the necessary calculations and transactions to perform a redemption between users meTokens and +// an accepted asset by the Index. +// A redemption includes the following actions: +// - Calculate the fee to charge to the user. +// - Calculate the amount of assets to return to the user +// - Calculate the amount of assets to be withdrawn from x/metoken reserves and x/leverage pools. +// - Withdraw the calculated portion from the x/metoken reserves. +// - Withdraw the calculated portion from the x/leverage liquidity pools. +// - Transfer meTokens from users account to x/metoken. +// - Burn meTokens. +// +// It returns: fee charged to the user, assets withdrawn from x/metoken and x/leverage +func (k Keeper) redeem(userAddr sdk.AccAddress, meToken sdk.Coin, assetDenom string) (redeemResponse, error) { + index, err := k.RegisteredIndex(meToken.Denom) + if err != nil { + return redeemResponse{}, err + } + + indexPrices, err := k.Prices(index) + if err != nil { + return redeemResponse{}, err + } + + balances, err := k.IndexBalances(meToken.Denom) + if err != nil { + return redeemResponse{}, err + } + + if !balances.MetokenSupply.IsPositive() { + return redeemResponse{}, fmt.Errorf("not enough %s supply", meToken.Denom) + } + + amountFromReserves, amountFromLeverage, err := k.calculateRedeem(index, indexPrices, meToken, assetDenom) + if err != nil { + return redeemResponse{}, err + } + + uTokenWithdrawn, err := k.withdrawFromLeverage(sdk.NewCoin(assetDenom, amountFromLeverage)) + if err != nil { + return redeemResponse{}, err + } + + // if there is a difference between the desired to withdraw from x/leverage and the withdrawn, + // take it from x/metoken reserves + tokenWithdrawn, err := k.leverageKeeper.ExchangeUToken(*k.ctx, uTokenWithdrawn) + if err != nil { + return redeemResponse{}, err + } + + if tokenWithdrawn.Amount.LT(amountFromLeverage) { + tokenDiff := amountFromLeverage.Sub(tokenWithdrawn.Amount) + amountFromReserves = amountFromReserves.Add(tokenDiff) + amountFromLeverage = amountFromLeverage.Sub(tokenDiff) + } + + i, balance := balances.AssetBalance(assetDenom) + if i < 0 { + return redeemResponse{}, sdkerrors.ErrNotFound.Wrapf( + "balance for denom %s not found", + assetDenom, + ) + } + + if balance.Reserved.LT(amountFromReserves) { + return redeemResponse{}, fmt.Errorf("not enough %s liquidity for redemption", assetDenom) + } + + fee, err := k.redeemFee( + index, + indexPrices, + sdk.NewCoin(assetDenom, amountFromReserves.Add(amountFromLeverage)), + ) + if err != nil { + return redeemResponse{}, err + } + + if err = k.bankKeeper.SendCoinsFromAccountToModule( + *k.ctx, + userAddr, + metoken.ModuleName, + sdk.NewCoins(meToken), + ); err != nil { + return redeemResponse{}, err + } + + toRedeem := sdk.NewCoin(assetDenom, amountFromReserves.Add(amountFromLeverage).Sub(fee.Amount)) + if err = k.bankKeeper.SendCoinsFromModuleToAccount( + *k.ctx, + metoken.ModuleName, + userAddr, + sdk.NewCoins(toRedeem), + ); err != nil { + return redeemResponse{}, err + } + + // once all the transactions are completed, update the index balances + // subtract burned meTokens from total supply + balances.MetokenSupply.Amount = balances.MetokenSupply.Amount.Sub(meToken.Amount) + // update reserved, leveraged and fee balances + balance.Reserved = balance.Reserved.Sub(amountFromReserves) + balance.Leveraged = balance.Leveraged.Sub(amountFromLeverage) + balance.Fees = balance.Fees.Add(fee.Amount) + balances.SetAssetBalance(balance) + + // save index balance + if err = k.setIndexBalances(balances); err != nil { + return redeemResponse{}, err + } + + // burn meTokens + if err = k.bankKeeper.BurnCoins(*k.ctx, metoken.ModuleName, sdk.NewCoins(meToken)); err != nil { + return redeemResponse{}, err + } + + return newRedeemResponse( + fee, + sdk.NewCoin(assetDenom, amountFromReserves), + sdk.NewCoin(assetDenom, amountFromLeverage), + ), nil +} + +// withdrawFromLeverage before withdrawing from x/leverage check if it's possible to withdraw the desired amount +// based on x/leverage module constrains. When the full amount is not available withdraw the max possible. +func (k Keeper) withdrawFromLeverage(tokensToWithdraw sdk.Coin) (sdk.Coin, error) { + uTokensFromLeverage, err := k.leverageKeeper.ExchangeToken(*k.ctx, tokensToWithdraw) + if err != nil { + return sdk.Coin{}, err + } + + availableUTokensFromLeverage, err := k.leverageKeeper.ModuleMaxWithdraw(*k.ctx, uTokensFromLeverage) + if err != nil { + return sdk.Coin{}, err + } + + uTokensToWithdraw := sdk.NewCoin(uTokensFromLeverage.Denom, availableUTokensFromLeverage) + if _, _, err = k.leverageKeeper.Withdraw( + *k.ctx, + authtypes.NewModuleAddress(metoken.ModuleName), + uTokensToWithdraw, + ); err != nil { + return sdk.Coin{}, err + } + + return uTokensToWithdraw, nil +} + +// calculateRedeem returns the fee to be charged to the user, +// the amount of assets to withdraw from x/metoken reserves and from x/leverage pools. +// The formulas used for the calculations are: +// +// assets_to_withdraw = metokens_to_burn * exchange_rate +// amount_from_reserves = assets_to_withdraw * reserve_portion +// amount_from_leverage = assets_to_withdraw - amount_from_reserves +// +// It returns the amount of assets to withdraw from x/metoken reserves and x/leverage liquidity pools. +func (k Keeper) calculateRedeem( + index metoken.Index, + indexPrices metoken.IndexPrices, + meToken sdk.Coin, + assetDenom string, +) (sdkmath.Int, sdkmath.Int, error) { + i, assetSettings := index.AcceptedAsset(assetDenom) + if i < 0 { + return sdkmath.ZeroInt(), sdkmath.ZeroInt(), sdkerrors.ErrNotFound.Wrapf( + "asset %s is not accepted in the index", + assetDenom, + ) + } + + amountToWithdraw, err := indexPrices.SwapRate(meToken, assetDenom) + if err != nil { + return sdkmath.ZeroInt(), sdkmath.ZeroInt(), err + } + + amountFromReserves := assetSettings.ReservePortion.MulInt(amountToWithdraw).TruncateInt() + amountFromLeverage := amountToWithdraw.Sub(amountFromReserves) + + return amountFromReserves, amountFromLeverage, nil +} diff --git a/x/metoken/keeper/swap.go b/x/metoken/keeper/swap.go new file mode 100644 index 0000000000..c7ab5e1d1e --- /dev/null +++ b/x/metoken/keeper/swap.go @@ -0,0 +1,219 @@ +package keeper + +import ( + "fmt" + + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + + "github.com/umee-network/umee/v5/x/metoken" +) + +// swapResponse wraps all the coins of a successful swap +type swapResponse struct { + meTokens sdk.Coin + fee sdk.Coin + reserved sdk.Coin + leveraged sdk.Coin +} + +func newSwapResponse(meTokens sdk.Coin, fee sdk.Coin, reserved sdk.Coin, leveraged sdk.Coin) swapResponse { + return swapResponse{ + meTokens: meTokens, + fee: fee, + reserved: reserved, + leveraged: leveraged, + } +} + +// swap executes all the necessary calculations and transactions to perform a swap between users asset and meToken. +// A swap includes the following actions: +// - Calculate the calculateFee to charge to the user. +// - Calculate the amount of meTokens to be minted. +// - Mint meTokens. +// - Calculate the amount of user's assets to send to x/metoken reserves and x/leverage pools. +// - Transfer the calculated portion to the x/metoken reserves. +// - Transfer the calculated portion to the x/leverage liquidity pools. +// - Transfer to the user the minted meTokens. +// +// It returns: minted meTokens, charged fee, assets transferred to reserves and assets transferred to x/leverage. +func (k Keeper) swap(userAddr sdk.AccAddress, meTokenDenom string, asset sdk.Coin) (swapResponse, error) { + index, err := k.RegisteredIndex(meTokenDenom) + if err != nil { + return swapResponse{}, err + } + + indexPrices, err := k.Prices(index) + if err != nil { + return swapResponse{}, err + } + + meTokenAmount, fee, amountToReserves, amountToLeverage, err := k.calculateSwap(index, indexPrices, asset) + if err != nil { + return swapResponse{}, err + } + + balances, err := k.IndexBalances(meTokenDenom) + if err != nil { + return swapResponse{}, err + } + + if balances.MetokenSupply.Amount.Add(meTokenAmount).GT(index.MaxSupply) { + return swapResponse{}, fmt.Errorf( + "not possible to mint the desired amount of %s, reaching the max supply", + meTokenDenom, + ) + } + + if err = k.bankKeeper.SendCoinsFromAccountToModule( + *k.ctx, + userAddr, + metoken.ModuleName, + sdk.NewCoins(asset), + ); err != nil { + return swapResponse{}, err + } + + supplied, err := k.supplyToLeverage(sdk.NewCoin(asset.Denom, amountToLeverage)) + if err != nil { + return swapResponse{}, err + } + + // adjust amount if supplied to x/leverage is less than the calculated amount + if supplied.LT(amountToLeverage) { + tokenDiff := amountToLeverage.Sub(supplied) + amountToReserves = amountToReserves.Add(tokenDiff) + amountToLeverage = amountToLeverage.Sub(tokenDiff) + } + + meTokens := sdk.NewCoins(sdk.NewCoin(meTokenDenom, meTokenAmount)) + if err = k.bankKeeper.MintCoins(*k.ctx, metoken.ModuleName, meTokens); err != nil { + return swapResponse{}, err + } + + if err = k.bankKeeper.SendCoinsFromModuleToAccount(*k.ctx, metoken.ModuleName, userAddr, meTokens); err != nil { + return swapResponse{}, err + } + + balances.MetokenSupply.Amount = balances.MetokenSupply.Amount.Add(meTokenAmount) + i, balance := balances.AssetBalance(asset.Denom) + if i < 0 { + return swapResponse{}, sdkerrors.ErrNotFound.Wrapf( + "balance for denom %s not found", + asset.Denom, + ) + } + + balance.Reserved = balance.Reserved.Add(amountToReserves) + balance.Leveraged = balance.Leveraged.Add(amountToLeverage) + balance.Fees = balance.Fees.Add(fee) + balances.SetAssetBalance(balance) + + if err = k.setIndexBalances(balances); err != nil { + return swapResponse{}, err + } + + return newSwapResponse( + sdk.NewCoin(meTokenDenom, meTokenAmount), + sdk.NewCoin(asset.Denom, fee), + sdk.NewCoin(asset.Denom, amountToReserves), + sdk.NewCoin(asset.Denom, amountToLeverage), + ), nil +} + +// supplyToLeverage before supplying to x/leverage check if it's possible to supply the desired amount +// based on x/leverage module constrains. When the full amount cannot be supplied, supply the max possible. +func (k Keeper) supplyToLeverage(tokensToSupply sdk.Coin) (sdkmath.Int, error) { + isLimited, availableToSupply, err := k.availableToSupply(tokensToSupply.Denom) + if err != nil { + return sdkmath.Int{}, err + } + + if isLimited { + if !availableToSupply.IsPositive() { + return sdkmath.ZeroInt(), nil + } + + if availableToSupply.LT(tokensToSupply.Amount) { + tokensToSupply.Amount = availableToSupply + } + } + + if _, err = k.leverageKeeper.Supply( + *k.ctx, + authtypes.NewModuleAddress(metoken.ModuleName), + tokensToSupply, + ); err != nil { + return sdkmath.Int{}, err + } + + return tokensToSupply.Amount, nil +} + +// availableToSupply calculates the max amount could be supplied to x/leverage. +// Returns true and the max available if it is limited or false if it's unlimited. +func (k Keeper) availableToSupply(denom string) (bool, sdkmath.Int, error) { + token, err := k.leverageKeeper.GetTokenSettings(*k.ctx, denom) + if err != nil { + return true, sdkmath.Int{}, err + } + + // when the max_supply is set to zero, the supply is unlimited + if token.MaxSupply.IsZero() { + return false, sdkmath.ZeroInt(), nil + } + + total, err := k.leverageKeeper.GetTotalSupply(*k.ctx, denom) + if err != nil { + return true, sdkmath.Int{}, err + } + + return true, token.MaxSupply.Sub(total.Amount), nil +} + +// calculateSwap returns the amount of meToken to send to the user, the fee to be charged to him, +// the amount of assets to send to x/metoken reserves and to x/leverage pools. +// The formulas used for the calculations are: +// +// assets_to_swap = assets_from_user - fee +// metokens_to_mint = assets_to_swap * exchange_rate +// amount_to_reserves = assets_to_swap * reserve_portion +// amount_to_leverage = assets_to_swap - amount_to_reserves +// +// It returns meTokens to be minted, fee to be charged, +// amount to transfer to x/metoken reserves and x/leverage liquidity pools +func (k Keeper) calculateSwap(index metoken.Index, indexPrices metoken.IndexPrices, asset sdk.Coin) ( + sdkmath.Int, + sdkmath.Int, + sdkmath.Int, + sdkmath.Int, + error, +) { + i, assetSettings := index.AcceptedAsset(asset.Denom) + if i < 0 { + return sdkmath.ZeroInt(), sdkmath.ZeroInt(), sdkmath.ZeroInt(), sdkmath.ZeroInt(), sdkerrors.ErrNotFound.Wrapf( + "asset %s is not accepted in the index", + asset.Denom, + ) + } + + fee, err := k.swapFee(index, indexPrices, asset) + if err != nil { + return sdkmath.ZeroInt(), sdkmath.ZeroInt(), sdkmath.ZeroInt(), sdkmath.ZeroInt(), err + } + + amountToSwap := asset.Amount.Sub(fee.Amount) + + meTokens, err := indexPrices.SwapRate(sdk.NewCoin(asset.Denom, amountToSwap), index.Denom) + if err != nil { + return sdkmath.ZeroInt(), sdkmath.ZeroInt(), sdkmath.ZeroInt(), sdkmath.ZeroInt(), err + } + + amountToReserves := assetSettings.ReservePortion.MulInt(amountToSwap).TruncateInt() + amountToLeverage := amountToSwap.Sub(amountToReserves) + + return meTokens, fee.Amount, amountToReserves, amountToLeverage, nil +} diff --git a/x/metoken/keeper/unit_test.go b/x/metoken/keeper/unit_test.go new file mode 100644 index 0000000000..8b8bb3a04a --- /dev/null +++ b/x/metoken/keeper/unit_test.go @@ -0,0 +1,51 @@ +package keeper + +import ( + "testing" + + "github.com/umee-network/umee/v5/x/metoken/mocks" + + "github.com/umee-network/umee/v5/x/metoken" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/types" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + + "github.com/umee-network/umee/v5/tests/tsdk" +) + +// initSimpleKeeper creates a simple keeper without external dependencies. +func initSimpleKeeper(t *testing.T) Keeper { + t.Parallel() + interfaceRegistry := types.NewInterfaceRegistry() + cdc := codec.NewProtoCodec(interfaceRegistry) + storeKey := storetypes.NewMemoryStoreKey("metoken") + kb := NewKeeperBuilder(cdc, storeKey, nil, nil, nil) + ctx, _ := tsdk.NewCtxOneStore(t, storeKey) + + return kb.Keeper(&ctx) +} + +// initMeUSDKeeper creates a keeper with external dependencies and with meUSD index and balance inserted. +func initMeUSDKeeper( + t *testing.T, + bankKeeper metoken.BankKeeper, + leverageKeeper metoken.LeverageKeeper, + oracleKeeper metoken.OracleKeeper, +) Keeper { + k := initSimpleKeeper(t) + k.bankKeeper = bankKeeper + k.leverageKeeper = leverageKeeper + k.oracleKeeper = oracleKeeper + + index := mocks.StableIndex(mocks.MeUSDDenom) + err := k.setRegisteredIndex(index) + require.NoError(t, err) + + balance := mocks.ValidUSDIndexBalances(mocks.MeUSDDenom) + err = k.setIndexBalances(balance) + + return k +} diff --git a/x/metoken/keys.go b/x/metoken/keys.go new file mode 100644 index 0000000000..9234cdcdf5 --- /dev/null +++ b/x/metoken/keys.go @@ -0,0 +1,9 @@ +package metoken + +const ( + // ModuleName defines the module name + ModuleName = "metoken" + + // StoreKey defines the primary module store key + StoreKey = ModuleName +) diff --git a/x/metoken/metoken.pb.go b/x/metoken/metoken.pb.go new file mode 100644 index 0000000000..e495692b93 --- /dev/null +++ b/x/metoken/metoken.pb.go @@ -0,0 +1,1420 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: umee/metoken/v1/metoken.proto + +package metoken + +import ( + cosmossdk_io_math "cosmossdk.io/math" + fmt "fmt" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// Params defines the parameters for the metoken module. +type Params struct { + // Reserves Re-balancing Frequency in seconds, determines how often the re-balancing of the module reserves will be + // triggered + RebalancingFrequency int64 `protobuf:"varint,1,opt,name=rebalancing_frequency,json=rebalancingFrequency,proto3" json:"rebalancing_frequency,omitempty"` + // Interest claiming frequency in seconds, determines how often metoken module will claim accrued interest from + // leverage module + ClaimingFrequency int64 `protobuf:"varint,2,opt,name=claiming_frequency,json=claimingFrequency,proto3" json:"claiming_frequency,omitempty"` +} + +func (m *Params) Reset() { *m = Params{} } +func (m *Params) String() string { return proto.CompactTextString(m) } +func (*Params) ProtoMessage() {} +func (*Params) Descriptor() ([]byte, []int) { + return fileDescriptor_dda977db8ad52437, []int{0} +} +func (m *Params) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Params.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 *Params) XXX_Merge(src proto.Message) { + xxx_messageInfo_Params.Merge(m, src) +} +func (m *Params) XXX_Size() int { + return m.Size() +} +func (m *Params) XXX_DiscardUnknown() { + xxx_messageInfo_Params.DiscardUnknown(m) +} + +var xxx_messageInfo_Params proto.InternalMessageInfo + +func (m *Params) GetRebalancingFrequency() int64 { + if m != nil { + return m.RebalancingFrequency + } + return 0 +} + +func (m *Params) GetClaimingFrequency() int64 { + if m != nil { + return m.ClaimingFrequency + } + return 0 +} + +// Index defines an index of assets that are allowed to swap and redeem for the Index's meToken, +// along with its metadata and parameters. +type Index struct { + // Denom is the denomination of the Index's meToken denom that will be given to user in exchange of accepted + // assets. + Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty"` + // MaxSupply is the maximum amount of Index's meTokens can be minted. + // A swap that requires to mint more Index's meToken than this value will result in an error. + // Must be a non negative value. 0 means that there is no limit. + MaxSupply cosmossdk_io_math.Int `protobuf:"bytes,2,opt,name=max_supply,json=maxSupply,proto3,customtype=cosmossdk.io/math.Int" json:"max_supply"` + // Exponent is the power of ten by which to multiply, in order to convert + // an amount of the meToken for the exchange operations. + // Valid value: must be the same as the oracle.Denom.exponent. + Exponent uint32 `protobuf:"varint,3,opt,name=exponent,proto3" json:"exponent,omitempty"` + // Fee contains fee parameters used for swap and redemption fee calculations for all underlying + // assets in this index. + Fee Fee `protobuf:"bytes,4,opt,name=fee,proto3" json:"fee"` + // Accepted Assets is the list of underlying Tokens that can be swapped and redeemed for the Index's meToken, + // along with their token-specific parameters. + AcceptedAssets []AcceptedAsset `protobuf:"bytes,5,rep,name=accepted_assets,json=acceptedAssets,proto3" json:"accepted_assets"` +} + +func (m *Index) Reset() { *m = Index{} } +func (m *Index) String() string { return proto.CompactTextString(m) } +func (*Index) ProtoMessage() {} +func (*Index) Descriptor() ([]byte, []int) { + return fileDescriptor_dda977db8ad52437, []int{1} +} +func (m *Index) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Index) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Index.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 *Index) XXX_Merge(src proto.Message) { + xxx_messageInfo_Index.Merge(m, src) +} +func (m *Index) XXX_Size() int { + return m.Size() +} +func (m *Index) XXX_DiscardUnknown() { + xxx_messageInfo_Index.DiscardUnknown(m) +} + +var xxx_messageInfo_Index proto.InternalMessageInfo + +func (m *Index) GetDenom() string { + if m != nil { + return m.Denom + } + return "" +} + +func (m *Index) GetExponent() uint32 { + if m != nil { + return m.Exponent + } + return 0 +} + +func (m *Index) GetFee() Fee { + if m != nil { + return m.Fee + } + return Fee{} +} + +func (m *Index) GetAcceptedAssets() []AcceptedAsset { + if m != nil { + return m.AcceptedAssets + } + return nil +} + +// Fee are the parameters used for the calculation of the fee to be applied for swaps and redemptions and charged to +// the user. The usage of these parameters is explained here: +// https://github.com/umee-network/umee/tree/main/x/metoken#dynamic-fee +type Fee struct { + // Min fee is the minimum fee to be charged to the user. The applied fee will tend to decrease down to this value, + // when the accepted asset is undersupplied in the index. It must be less than Balanced and Max fees. + // Valid values: 0-1. + MinFee github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,1,opt,name=min_fee,json=minFee,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"min_fee"` + // Balanced fee is the fee to be charged to the user when the index is balanced. It must be greater than min_fee and + // lower than max_fee + // Valid values: 0-1. + BalancedFee github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,2,opt,name=balanced_fee,json=balancedFee,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"balanced_fee"` + // Max fee is the maximum fee to be charged to the user. The applied fee will tend to increase up to this value, + // when the accepted asset is oversupplied in the index. It must be greater than Min and Balanced fee. + // Valid values: 0-1. + MaxFee github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,3,opt,name=max_fee,json=maxFee,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"max_fee"` +} + +func (m *Fee) Reset() { *m = Fee{} } +func (m *Fee) String() string { return proto.CompactTextString(m) } +func (*Fee) ProtoMessage() {} +func (*Fee) Descriptor() ([]byte, []int) { + return fileDescriptor_dda977db8ad52437, []int{2} +} +func (m *Fee) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Fee) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Fee.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 *Fee) XXX_Merge(src proto.Message) { + xxx_messageInfo_Fee.Merge(m, src) +} +func (m *Fee) XXX_Size() int { + return m.Size() +} +func (m *Fee) XXX_DiscardUnknown() { + xxx_messageInfo_Fee.DiscardUnknown(m) +} + +var xxx_messageInfo_Fee proto.InternalMessageInfo + +// AcceptedAsset is an asset that is accepted to participate in the Index's swaps and redemptions, along with its +// metadata and parameters +type AcceptedAsset struct { + // Denom is the denomination of the underlying asset. Must be the base + // denom as registered in the Bank module (so IBC denom for IBC tokens). + Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty"` + // Reserve portion is the portion of swapped assets that will be kept in the metoken module as reserves, + // instead of supplied to the leverage module. It is also the + // portion that will be taken from metoken module reserves when a redemption occurs. + // Valid values: 0-1. + ReservePortion github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,2,opt,name=reserve_portion,json=reservePortion,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"reserve_portion"` + // Target allocation is the portion of an accepted asset the Index is targeting to have. The sum of + // target allocations of every accepted asset in the Index should be equal to 1. + // Valid values: 0-1. + TargetAllocation github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,3,opt,name=target_allocation,json=targetAllocation,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"target_allocation"` +} + +func (m *AcceptedAsset) Reset() { *m = AcceptedAsset{} } +func (m *AcceptedAsset) String() string { return proto.CompactTextString(m) } +func (*AcceptedAsset) ProtoMessage() {} +func (*AcceptedAsset) Descriptor() ([]byte, []int) { + return fileDescriptor_dda977db8ad52437, []int{3} +} +func (m *AcceptedAsset) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AcceptedAsset) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AcceptedAsset.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 *AcceptedAsset) XXX_Merge(src proto.Message) { + xxx_messageInfo_AcceptedAsset.Merge(m, src) +} +func (m *AcceptedAsset) XXX_Size() int { + return m.Size() +} +func (m *AcceptedAsset) XXX_DiscardUnknown() { + xxx_messageInfo_AcceptedAsset.DiscardUnknown(m) +} + +var xxx_messageInfo_AcceptedAsset proto.InternalMessageInfo + +func (m *AcceptedAsset) GetDenom() string { + if m != nil { + return m.Denom + } + return "" +} + +func init() { + proto.RegisterType((*Params)(nil), "umeenetwork.umee.metoken.v1.Params") + proto.RegisterType((*Index)(nil), "umeenetwork.umee.metoken.v1.Index") + proto.RegisterType((*Fee)(nil), "umeenetwork.umee.metoken.v1.Fee") + proto.RegisterType((*AcceptedAsset)(nil), "umeenetwork.umee.metoken.v1.AcceptedAsset") +} + +func init() { proto.RegisterFile("umee/metoken/v1/metoken.proto", fileDescriptor_dda977db8ad52437) } + +var fileDescriptor_dda977db8ad52437 = []byte{ + // 515 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x93, 0xc1, 0x6e, 0xd3, 0x40, + 0x10, 0x86, 0xe3, 0x38, 0x09, 0x64, 0x43, 0x5b, 0xba, 0x4a, 0xa5, 0xa8, 0xa8, 0x4e, 0xd4, 0x03, + 0x0a, 0x48, 0x59, 0xab, 0xad, 0x90, 0x10, 0xe2, 0x92, 0x80, 0x82, 0x7a, 0x2b, 0xe6, 0x80, 0x80, + 0x83, 0xb5, 0xb1, 0xa7, 0xa9, 0x95, 0xec, 0xae, 0xd9, 0xdd, 0x04, 0xf7, 0x2d, 0x10, 0x4f, 0xc0, + 0xe3, 0xf4, 0xd8, 0x23, 0xe2, 0x50, 0x41, 0x72, 0xe1, 0xc8, 0x23, 0x20, 0xaf, 0xed, 0x28, 0x3d, + 0xd0, 0x43, 0x4e, 0x9e, 0xf1, 0xcc, 0xff, 0xed, 0xcc, 0xec, 0x2c, 0x3a, 0x98, 0x31, 0x00, 0x97, + 0x81, 0x16, 0x13, 0xe0, 0xee, 0xfc, 0xa8, 0x30, 0x49, 0x2c, 0x85, 0x16, 0xf8, 0x51, 0x1a, 0xe6, + 0xa0, 0xbf, 0x08, 0x39, 0x21, 0xa9, 0x4d, 0x8a, 0xf8, 0xfc, 0x68, 0xbf, 0x39, 0x16, 0x63, 0x61, + 0xf2, 0xdc, 0xd4, 0xca, 0x24, 0x87, 0x12, 0xd5, 0xce, 0xa8, 0xa4, 0x4c, 0xe1, 0x13, 0xb4, 0x27, + 0x61, 0x44, 0xa7, 0x94, 0x07, 0x11, 0x1f, 0xfb, 0xe7, 0x12, 0x3e, 0xcf, 0x80, 0x07, 0x97, 0x2d, + 0xab, 0x63, 0x75, 0x6d, 0xaf, 0xb9, 0x16, 0x1c, 0x16, 0x31, 0xdc, 0x43, 0x38, 0x98, 0xd2, 0x88, + 0xdd, 0x56, 0x94, 0x8d, 0x62, 0xb7, 0x88, 0xac, 0xd2, 0x5f, 0x54, 0xfe, 0x7c, 0x6f, 0x5b, 0x87, + 0xdf, 0xca, 0xa8, 0x7a, 0xca, 0x43, 0x48, 0x70, 0x13, 0x55, 0x43, 0xe0, 0x82, 0x99, 0x33, 0xea, + 0x5e, 0xe6, 0xe0, 0x97, 0x08, 0x31, 0x9a, 0xf8, 0x6a, 0x16, 0xc7, 0xd3, 0x0c, 0x56, 0x1f, 0x1c, + 0x5c, 0xdd, 0xb4, 0x4b, 0x3f, 0x6f, 0xda, 0x7b, 0x81, 0x50, 0x4c, 0x28, 0x15, 0x4e, 0x48, 0x24, + 0x5c, 0x46, 0xf5, 0x05, 0x39, 0xe5, 0xda, 0xab, 0x33, 0x9a, 0xbc, 0x33, 0xf9, 0x78, 0x1f, 0xdd, + 0x87, 0x24, 0x16, 0x1c, 0xb8, 0x6e, 0xd9, 0x1d, 0xab, 0xbb, 0xe5, 0xad, 0x7c, 0xfc, 0x1c, 0xd9, + 0xe7, 0x00, 0xad, 0x4a, 0xc7, 0xea, 0x36, 0x8e, 0x3b, 0xe4, 0x8e, 0x71, 0x91, 0x21, 0xc0, 0xa0, + 0x92, 0x1e, 0xea, 0xa5, 0x12, 0xfc, 0x01, 0xed, 0xd0, 0x20, 0x80, 0x58, 0x43, 0xe8, 0x53, 0xa5, + 0x40, 0xab, 0x56, 0xb5, 0x63, 0x77, 0x1b, 0xc7, 0x4f, 0xef, 0xa4, 0xf4, 0x73, 0x4d, 0x3f, 0x95, + 0xe4, 0xbc, 0x6d, 0xba, 0xfe, 0x53, 0xe5, 0x43, 0xf9, 0x6b, 0x21, 0x7b, 0x08, 0x80, 0xdf, 0xa0, + 0x7b, 0x2c, 0xe2, 0x7e, 0x5a, 0xa6, 0x19, 0xca, 0x80, 0xe4, 0x9d, 0x3f, 0x1e, 0x47, 0xfa, 0x62, + 0x36, 0x22, 0x81, 0x60, 0x6e, 0x36, 0x84, 0xfc, 0xd3, 0x53, 0xe1, 0xc4, 0xd5, 0x97, 0x31, 0x28, + 0xf2, 0x1a, 0x02, 0xaf, 0xc6, 0x22, 0x9e, 0x82, 0xde, 0xa2, 0x07, 0xd9, 0x85, 0x41, 0x68, 0x68, + 0xe5, 0x8d, 0x68, 0x8d, 0x82, 0x51, 0xd4, 0x46, 0x13, 0x43, 0xb3, 0x37, 0xac, 0x8d, 0x26, 0x43, + 0x80, 0xbc, 0xe5, 0xdf, 0x16, 0xda, 0xba, 0x35, 0xa0, 0xff, 0xec, 0xc3, 0x7b, 0xb4, 0x23, 0x41, + 0x81, 0x9c, 0x83, 0x1f, 0x0b, 0xa9, 0x23, 0xc1, 0x37, 0x6c, 0x66, 0x3b, 0xc7, 0x9c, 0x65, 0x14, + 0xfc, 0x09, 0xed, 0x6a, 0x2a, 0xc7, 0xa0, 0x7d, 0x3a, 0x9d, 0x8a, 0x80, 0x1a, 0xf4, 0x66, 0x9d, + 0x3d, 0xcc, 0x40, 0xfd, 0x15, 0x27, 0xeb, 0x71, 0xf0, 0xea, 0x6a, 0xe1, 0x58, 0xd7, 0x0b, 0xc7, + 0xfa, 0xb5, 0x70, 0xac, 0xaf, 0x4b, 0xa7, 0x74, 0xbd, 0x74, 0x4a, 0x3f, 0x96, 0x4e, 0xe9, 0xe3, + 0x93, 0x35, 0x72, 0xba, 0x36, 0xbd, 0x7c, 0x87, 0x8c, 0xe3, 0xce, 0x9f, 0xb9, 0x49, 0xf1, 0xba, + 0x47, 0x35, 0xf3, 0x56, 0x4f, 0xfe, 0x05, 0x00, 0x00, 0xff, 0xff, 0x31, 0x6e, 0x55, 0xc2, 0xff, + 0x03, 0x00, 0x00, +} + +func (this *Params) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Params) + if !ok { + that2, ok := that.(Params) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.RebalancingFrequency != that1.RebalancingFrequency { + return false + } + if this.ClaimingFrequency != that1.ClaimingFrequency { + return false + } + return true +} +func (this *Index) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Index) + if !ok { + that2, ok := that.(Index) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Denom != that1.Denom { + return false + } + if !this.MaxSupply.Equal(that1.MaxSupply) { + return false + } + if this.Exponent != that1.Exponent { + return false + } + if !this.Fee.Equal(&that1.Fee) { + return false + } + if len(this.AcceptedAssets) != len(that1.AcceptedAssets) { + return false + } + for i := range this.AcceptedAssets { + if !this.AcceptedAssets[i].Equal(&that1.AcceptedAssets[i]) { + return false + } + } + return true +} +func (this *Fee) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Fee) + if !ok { + that2, ok := that.(Fee) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !this.MinFee.Equal(that1.MinFee) { + return false + } + if !this.BalancedFee.Equal(that1.BalancedFee) { + return false + } + if !this.MaxFee.Equal(that1.MaxFee) { + return false + } + return true +} +func (this *AcceptedAsset) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*AcceptedAsset) + if !ok { + that2, ok := that.(AcceptedAsset) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Denom != that1.Denom { + return false + } + if !this.ReservePortion.Equal(that1.ReservePortion) { + return false + } + if !this.TargetAllocation.Equal(that1.TargetAllocation) { + return false + } + return true +} +func (m *Params) 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 *Params) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.ClaimingFrequency != 0 { + i = encodeVarintMetoken(dAtA, i, uint64(m.ClaimingFrequency)) + i-- + dAtA[i] = 0x10 + } + if m.RebalancingFrequency != 0 { + i = encodeVarintMetoken(dAtA, i, uint64(m.RebalancingFrequency)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *Index) 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 *Index) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Index) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.AcceptedAssets) > 0 { + for iNdEx := len(m.AcceptedAssets) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.AcceptedAssets[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetoken(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + } + { + size, err := m.Fee.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetoken(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + if m.Exponent != 0 { + i = encodeVarintMetoken(dAtA, i, uint64(m.Exponent)) + i-- + dAtA[i] = 0x18 + } + { + size := m.MaxSupply.Size() + i -= size + if _, err := m.MaxSupply.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintMetoken(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintMetoken(dAtA, i, uint64(len(m.Denom))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *Fee) 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 *Fee) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Fee) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.MaxFee.Size() + i -= size + if _, err := m.MaxFee.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintMetoken(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + { + size := m.BalancedFee.Size() + i -= size + if _, err := m.BalancedFee.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintMetoken(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + { + size := m.MinFee.Size() + i -= size + if _, err := m.MinFee.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintMetoken(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *AcceptedAsset) 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 *AcceptedAsset) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AcceptedAsset) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.TargetAllocation.Size() + i -= size + if _, err := m.TargetAllocation.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintMetoken(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + { + size := m.ReservePortion.Size() + i -= size + if _, err := m.ReservePortion.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintMetoken(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintMetoken(dAtA, i, uint64(len(m.Denom))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintMetoken(dAtA []byte, offset int, v uint64) int { + offset -= sovMetoken(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Params) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.RebalancingFrequency != 0 { + n += 1 + sovMetoken(uint64(m.RebalancingFrequency)) + } + if m.ClaimingFrequency != 0 { + n += 1 + sovMetoken(uint64(m.ClaimingFrequency)) + } + return n +} + +func (m *Index) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Denom) + if l > 0 { + n += 1 + l + sovMetoken(uint64(l)) + } + l = m.MaxSupply.Size() + n += 1 + l + sovMetoken(uint64(l)) + if m.Exponent != 0 { + n += 1 + sovMetoken(uint64(m.Exponent)) + } + l = m.Fee.Size() + n += 1 + l + sovMetoken(uint64(l)) + if len(m.AcceptedAssets) > 0 { + for _, e := range m.AcceptedAssets { + l = e.Size() + n += 1 + l + sovMetoken(uint64(l)) + } + } + return n +} + +func (m *Fee) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.MinFee.Size() + n += 1 + l + sovMetoken(uint64(l)) + l = m.BalancedFee.Size() + n += 1 + l + sovMetoken(uint64(l)) + l = m.MaxFee.Size() + n += 1 + l + sovMetoken(uint64(l)) + return n +} + +func (m *AcceptedAsset) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Denom) + if l > 0 { + n += 1 + l + sovMetoken(uint64(l)) + } + l = m.ReservePortion.Size() + n += 1 + l + sovMetoken(uint64(l)) + l = m.TargetAllocation.Size() + n += 1 + l + sovMetoken(uint64(l)) + return n +} + +func sovMetoken(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozMetoken(x uint64) (n int) { + return sovMetoken(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Params) 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 ErrIntOverflowMetoken + } + 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: Params: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field RebalancingFrequency", wireType) + } + m.RebalancingFrequency = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetoken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.RebalancingFrequency |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ClaimingFrequency", wireType) + } + m.ClaimingFrequency = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetoken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ClaimingFrequency |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipMetoken(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMetoken + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Index) 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 ErrIntOverflowMetoken + } + 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: Index: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Index: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetoken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthMetoken + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMetoken + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxSupply", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetoken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthMetoken + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMetoken + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MaxSupply.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Exponent", wireType) + } + m.Exponent = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetoken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Exponent |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Fee", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetoken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetoken + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetoken + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Fee.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AcceptedAssets", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetoken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetoken + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetoken + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AcceptedAssets = append(m.AcceptedAssets, AcceptedAsset{}) + if err := m.AcceptedAssets[len(m.AcceptedAssets)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipMetoken(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMetoken + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Fee) 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 ErrIntOverflowMetoken + } + 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: Fee: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Fee: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MinFee", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetoken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthMetoken + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMetoken + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MinFee.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BalancedFee", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetoken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthMetoken + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMetoken + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.BalancedFee.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxFee", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetoken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthMetoken + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMetoken + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MaxFee.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipMetoken(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMetoken + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AcceptedAsset) 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 ErrIntOverflowMetoken + } + 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: AcceptedAsset: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AcceptedAsset: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetoken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthMetoken + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMetoken + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ReservePortion", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetoken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthMetoken + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMetoken + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ReservePortion.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TargetAllocation", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetoken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthMetoken + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMetoken + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.TargetAllocation.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipMetoken(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMetoken + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipMetoken(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowMetoken + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowMetoken + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowMetoken + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthMetoken + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupMetoken + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthMetoken + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthMetoken = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowMetoken = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupMetoken = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/metoken/mocks/generate.go b/x/metoken/mocks/generate.go new file mode 100644 index 0000000000..2b90f310f7 --- /dev/null +++ b/x/metoken/mocks/generate.go @@ -0,0 +1,4 @@ +package mocks + +// Use this command to generate mocks for x/metoken Keeper interfaces +//go:generate go-mockgen -f -i BankKeeper -i LeverageKeeper -i OracleKeeper -o ./keepers.go ../ diff --git a/x/metoken/mocks/keepers.go b/x/metoken/mocks/keepers.go new file mode 100644 index 0000000000..9116e9fd8d --- /dev/null +++ b/x/metoken/mocks/keepers.go @@ -0,0 +1,1612 @@ +// Code generated by go-mockgen 1.3.7; DO NOT EDIT. + +package mocks + +import ( + "sync" + + math "cosmossdk.io/math" + types "github.com/cosmos/cosmos-sdk/types" + types1 "github.com/umee-network/umee/v5/x/leverage/types" + metoken "github.com/umee-network/umee/v5/x/metoken" + types2 "github.com/umee-network/umee/v5/x/oracle/types" +) + +// MockBankKeeper is a mock implementation of the BankKeeper interface (from +// the package github.com/umee-network/umee/v5/x/metoken) used for unit +// testing. +type MockBankKeeper struct { + // BurnCoinsFunc is an instance of a mock function object controlling + // the behavior of the method BurnCoins. + BurnCoinsFunc *BankKeeperBurnCoinsFunc + // MintCoinsFunc is an instance of a mock function object controlling + // the behavior of the method MintCoins. + MintCoinsFunc *BankKeeperMintCoinsFunc + // SendCoinsFromAccountToModuleFunc is an instance of a mock function + // object controlling the behavior of the method + // SendCoinsFromAccountToModule. + SendCoinsFromAccountToModuleFunc *BankKeeperSendCoinsFromAccountToModuleFunc + // SendCoinsFromModuleToAccountFunc is an instance of a mock function + // object controlling the behavior of the method + // SendCoinsFromModuleToAccount. + SendCoinsFromModuleToAccountFunc *BankKeeperSendCoinsFromModuleToAccountFunc +} + +// NewMockBankKeeper creates a new mock of the BankKeeper interface. All +// methods return zero values for all results, unless overwritten. +func NewMockBankKeeper() *MockBankKeeper { + return &MockBankKeeper{ + BurnCoinsFunc: &BankKeeperBurnCoinsFunc{ + defaultHook: func(types.Context, string, types.Coins) (r0 error) { + return + }, + }, + MintCoinsFunc: &BankKeeperMintCoinsFunc{ + defaultHook: func(types.Context, string, types.Coins) (r0 error) { + return + }, + }, + SendCoinsFromAccountToModuleFunc: &BankKeeperSendCoinsFromAccountToModuleFunc{ + defaultHook: func(types.Context, types.AccAddress, string, types.Coins) (r0 error) { + return + }, + }, + SendCoinsFromModuleToAccountFunc: &BankKeeperSendCoinsFromModuleToAccountFunc{ + defaultHook: func(types.Context, string, types.AccAddress, types.Coins) (r0 error) { + return + }, + }, + } +} + +// NewStrictMockBankKeeper creates a new mock of the BankKeeper interface. +// All methods panic on invocation, unless overwritten. +func NewStrictMockBankKeeper() *MockBankKeeper { + return &MockBankKeeper{ + BurnCoinsFunc: &BankKeeperBurnCoinsFunc{ + defaultHook: func(types.Context, string, types.Coins) error { + panic("unexpected invocation of MockBankKeeper.BurnCoins") + }, + }, + MintCoinsFunc: &BankKeeperMintCoinsFunc{ + defaultHook: func(types.Context, string, types.Coins) error { + panic("unexpected invocation of MockBankKeeper.MintCoins") + }, + }, + SendCoinsFromAccountToModuleFunc: &BankKeeperSendCoinsFromAccountToModuleFunc{ + defaultHook: func(types.Context, types.AccAddress, string, types.Coins) error { + panic("unexpected invocation of MockBankKeeper.SendCoinsFromAccountToModule") + }, + }, + SendCoinsFromModuleToAccountFunc: &BankKeeperSendCoinsFromModuleToAccountFunc{ + defaultHook: func(types.Context, string, types.AccAddress, types.Coins) error { + panic("unexpected invocation of MockBankKeeper.SendCoinsFromModuleToAccount") + }, + }, + } +} + +// NewMockBankKeeperFrom creates a new mock of the MockBankKeeper interface. +// All methods delegate to the given implementation, unless overwritten. +func NewMockBankKeeperFrom(i metoken.BankKeeper) *MockBankKeeper { + return &MockBankKeeper{ + BurnCoinsFunc: &BankKeeperBurnCoinsFunc{ + defaultHook: i.BurnCoins, + }, + MintCoinsFunc: &BankKeeperMintCoinsFunc{ + defaultHook: i.MintCoins, + }, + SendCoinsFromAccountToModuleFunc: &BankKeeperSendCoinsFromAccountToModuleFunc{ + defaultHook: i.SendCoinsFromAccountToModule, + }, + SendCoinsFromModuleToAccountFunc: &BankKeeperSendCoinsFromModuleToAccountFunc{ + defaultHook: i.SendCoinsFromModuleToAccount, + }, + } +} + +// BankKeeperBurnCoinsFunc describes the behavior when the BurnCoins method +// of the parent MockBankKeeper instance is invoked. +type BankKeeperBurnCoinsFunc struct { + defaultHook func(types.Context, string, types.Coins) error + hooks []func(types.Context, string, types.Coins) error + history []BankKeeperBurnCoinsFuncCall + mutex sync.Mutex +} + +// BurnCoins delegates to the next hook function in the queue and stores the +// parameter and result values of this invocation. +func (m *MockBankKeeper) BurnCoins(v0 types.Context, v1 string, v2 types.Coins) error { + r0 := m.BurnCoinsFunc.nextHook()(v0, v1, v2) + m.BurnCoinsFunc.appendCall(BankKeeperBurnCoinsFuncCall{v0, v1, v2, r0}) + return r0 +} + +// SetDefaultHook sets function that is called when the BurnCoins method of +// the parent MockBankKeeper instance is invoked and the hook queue is +// empty. +func (f *BankKeeperBurnCoinsFunc) SetDefaultHook(hook func(types.Context, string, types.Coins) error) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// BurnCoins method of the parent MockBankKeeper instance invokes the hook +// at the front of the queue and discards it. After the queue is empty, the +// default hook function is invoked for any future action. +func (f *BankKeeperBurnCoinsFunc) PushHook(hook func(types.Context, string, types.Coins) error) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultHook with a function that returns the +// given values. +func (f *BankKeeperBurnCoinsFunc) SetDefaultReturn(r0 error) { + f.SetDefaultHook(func(types.Context, string, types.Coins) error { + return r0 + }) +} + +// PushReturn calls PushHook with a function that returns the given values. +func (f *BankKeeperBurnCoinsFunc) PushReturn(r0 error) { + f.PushHook(func(types.Context, string, types.Coins) error { + return r0 + }) +} + +func (f *BankKeeperBurnCoinsFunc) nextHook() func(types.Context, string, types.Coins) error { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *BankKeeperBurnCoinsFunc) appendCall(r0 BankKeeperBurnCoinsFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of BankKeeperBurnCoinsFuncCall objects +// describing the invocations of this function. +func (f *BankKeeperBurnCoinsFunc) History() []BankKeeperBurnCoinsFuncCall { + f.mutex.Lock() + history := make([]BankKeeperBurnCoinsFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// BankKeeperBurnCoinsFuncCall is an object that describes an invocation of +// method BurnCoins on an instance of MockBankKeeper. +type BankKeeperBurnCoinsFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 types.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 string + // Arg2 is the value of the 3rd argument passed to this method + // invocation. + Arg2 types.Coins + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c BankKeeperBurnCoinsFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1, c.Arg2} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c BankKeeperBurnCoinsFuncCall) Results() []interface{} { + return []interface{}{c.Result0} +} + +// BankKeeperMintCoinsFunc describes the behavior when the MintCoins method +// of the parent MockBankKeeper instance is invoked. +type BankKeeperMintCoinsFunc struct { + defaultHook func(types.Context, string, types.Coins) error + hooks []func(types.Context, string, types.Coins) error + history []BankKeeperMintCoinsFuncCall + mutex sync.Mutex +} + +// MintCoins delegates to the next hook function in the queue and stores the +// parameter and result values of this invocation. +func (m *MockBankKeeper) MintCoins(v0 types.Context, v1 string, v2 types.Coins) error { + r0 := m.MintCoinsFunc.nextHook()(v0, v1, v2) + m.MintCoinsFunc.appendCall(BankKeeperMintCoinsFuncCall{v0, v1, v2, r0}) + return r0 +} + +// SetDefaultHook sets function that is called when the MintCoins method of +// the parent MockBankKeeper instance is invoked and the hook queue is +// empty. +func (f *BankKeeperMintCoinsFunc) SetDefaultHook(hook func(types.Context, string, types.Coins) error) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// MintCoins method of the parent MockBankKeeper instance invokes the hook +// at the front of the queue and discards it. After the queue is empty, the +// default hook function is invoked for any future action. +func (f *BankKeeperMintCoinsFunc) PushHook(hook func(types.Context, string, types.Coins) error) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultHook with a function that returns the +// given values. +func (f *BankKeeperMintCoinsFunc) SetDefaultReturn(r0 error) { + f.SetDefaultHook(func(types.Context, string, types.Coins) error { + return r0 + }) +} + +// PushReturn calls PushHook with a function that returns the given values. +func (f *BankKeeperMintCoinsFunc) PushReturn(r0 error) { + f.PushHook(func(types.Context, string, types.Coins) error { + return r0 + }) +} + +func (f *BankKeeperMintCoinsFunc) nextHook() func(types.Context, string, types.Coins) error { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *BankKeeperMintCoinsFunc) appendCall(r0 BankKeeperMintCoinsFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of BankKeeperMintCoinsFuncCall objects +// describing the invocations of this function. +func (f *BankKeeperMintCoinsFunc) History() []BankKeeperMintCoinsFuncCall { + f.mutex.Lock() + history := make([]BankKeeperMintCoinsFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// BankKeeperMintCoinsFuncCall is an object that describes an invocation of +// method MintCoins on an instance of MockBankKeeper. +type BankKeeperMintCoinsFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 types.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 string + // Arg2 is the value of the 3rd argument passed to this method + // invocation. + Arg2 types.Coins + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c BankKeeperMintCoinsFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1, c.Arg2} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c BankKeeperMintCoinsFuncCall) Results() []interface{} { + return []interface{}{c.Result0} +} + +// BankKeeperSendCoinsFromAccountToModuleFunc describes the behavior when +// the SendCoinsFromAccountToModule method of the parent MockBankKeeper +// instance is invoked. +type BankKeeperSendCoinsFromAccountToModuleFunc struct { + defaultHook func(types.Context, types.AccAddress, string, types.Coins) error + hooks []func(types.Context, types.AccAddress, string, types.Coins) error + history []BankKeeperSendCoinsFromAccountToModuleFuncCall + mutex sync.Mutex +} + +// SendCoinsFromAccountToModule delegates to the next hook function in the +// queue and stores the parameter and result values of this invocation. +func (m *MockBankKeeper) SendCoinsFromAccountToModule(v0 types.Context, v1 types.AccAddress, v2 string, v3 types.Coins) error { + r0 := m.SendCoinsFromAccountToModuleFunc.nextHook()(v0, v1, v2, v3) + m.SendCoinsFromAccountToModuleFunc.appendCall(BankKeeperSendCoinsFromAccountToModuleFuncCall{v0, v1, v2, v3, r0}) + return r0 +} + +// SetDefaultHook sets function that is called when the +// SendCoinsFromAccountToModule method of the parent MockBankKeeper instance +// is invoked and the hook queue is empty. +func (f *BankKeeperSendCoinsFromAccountToModuleFunc) SetDefaultHook(hook func(types.Context, types.AccAddress, string, types.Coins) error) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// SendCoinsFromAccountToModule method of the parent MockBankKeeper instance +// invokes the hook at the front of the queue and discards it. After the +// queue is empty, the default hook function is invoked for any future +// action. +func (f *BankKeeperSendCoinsFromAccountToModuleFunc) PushHook(hook func(types.Context, types.AccAddress, string, types.Coins) error) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultHook with a function that returns the +// given values. +func (f *BankKeeperSendCoinsFromAccountToModuleFunc) SetDefaultReturn(r0 error) { + f.SetDefaultHook(func(types.Context, types.AccAddress, string, types.Coins) error { + return r0 + }) +} + +// PushReturn calls PushHook with a function that returns the given values. +func (f *BankKeeperSendCoinsFromAccountToModuleFunc) PushReturn(r0 error) { + f.PushHook(func(types.Context, types.AccAddress, string, types.Coins) error { + return r0 + }) +} + +func (f *BankKeeperSendCoinsFromAccountToModuleFunc) nextHook() func(types.Context, types.AccAddress, string, types.Coins) error { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *BankKeeperSendCoinsFromAccountToModuleFunc) appendCall(r0 BankKeeperSendCoinsFromAccountToModuleFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of +// BankKeeperSendCoinsFromAccountToModuleFuncCall objects describing the +// invocations of this function. +func (f *BankKeeperSendCoinsFromAccountToModuleFunc) History() []BankKeeperSendCoinsFromAccountToModuleFuncCall { + f.mutex.Lock() + history := make([]BankKeeperSendCoinsFromAccountToModuleFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// BankKeeperSendCoinsFromAccountToModuleFuncCall is an object that +// describes an invocation of method SendCoinsFromAccountToModule on an +// instance of MockBankKeeper. +type BankKeeperSendCoinsFromAccountToModuleFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 types.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 types.AccAddress + // Arg2 is the value of the 3rd argument passed to this method + // invocation. + Arg2 string + // Arg3 is the value of the 4th argument passed to this method + // invocation. + Arg3 types.Coins + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c BankKeeperSendCoinsFromAccountToModuleFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1, c.Arg2, c.Arg3} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c BankKeeperSendCoinsFromAccountToModuleFuncCall) Results() []interface{} { + return []interface{}{c.Result0} +} + +// BankKeeperSendCoinsFromModuleToAccountFunc describes the behavior when +// the SendCoinsFromModuleToAccount method of the parent MockBankKeeper +// instance is invoked. +type BankKeeperSendCoinsFromModuleToAccountFunc struct { + defaultHook func(types.Context, string, types.AccAddress, types.Coins) error + hooks []func(types.Context, string, types.AccAddress, types.Coins) error + history []BankKeeperSendCoinsFromModuleToAccountFuncCall + mutex sync.Mutex +} + +// SendCoinsFromModuleToAccount delegates to the next hook function in the +// queue and stores the parameter and result values of this invocation. +func (m *MockBankKeeper) SendCoinsFromModuleToAccount(v0 types.Context, v1 string, v2 types.AccAddress, v3 types.Coins) error { + r0 := m.SendCoinsFromModuleToAccountFunc.nextHook()(v0, v1, v2, v3) + m.SendCoinsFromModuleToAccountFunc.appendCall(BankKeeperSendCoinsFromModuleToAccountFuncCall{v0, v1, v2, v3, r0}) + return r0 +} + +// SetDefaultHook sets function that is called when the +// SendCoinsFromModuleToAccount method of the parent MockBankKeeper instance +// is invoked and the hook queue is empty. +func (f *BankKeeperSendCoinsFromModuleToAccountFunc) SetDefaultHook(hook func(types.Context, string, types.AccAddress, types.Coins) error) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// SendCoinsFromModuleToAccount method of the parent MockBankKeeper instance +// invokes the hook at the front of the queue and discards it. After the +// queue is empty, the default hook function is invoked for any future +// action. +func (f *BankKeeperSendCoinsFromModuleToAccountFunc) PushHook(hook func(types.Context, string, types.AccAddress, types.Coins) error) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultHook with a function that returns the +// given values. +func (f *BankKeeperSendCoinsFromModuleToAccountFunc) SetDefaultReturn(r0 error) { + f.SetDefaultHook(func(types.Context, string, types.AccAddress, types.Coins) error { + return r0 + }) +} + +// PushReturn calls PushHook with a function that returns the given values. +func (f *BankKeeperSendCoinsFromModuleToAccountFunc) PushReturn(r0 error) { + f.PushHook(func(types.Context, string, types.AccAddress, types.Coins) error { + return r0 + }) +} + +func (f *BankKeeperSendCoinsFromModuleToAccountFunc) nextHook() func(types.Context, string, types.AccAddress, types.Coins) error { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *BankKeeperSendCoinsFromModuleToAccountFunc) appendCall(r0 BankKeeperSendCoinsFromModuleToAccountFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of +// BankKeeperSendCoinsFromModuleToAccountFuncCall objects describing the +// invocations of this function. +func (f *BankKeeperSendCoinsFromModuleToAccountFunc) History() []BankKeeperSendCoinsFromModuleToAccountFuncCall { + f.mutex.Lock() + history := make([]BankKeeperSendCoinsFromModuleToAccountFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// BankKeeperSendCoinsFromModuleToAccountFuncCall is an object that +// describes an invocation of method SendCoinsFromModuleToAccount on an +// instance of MockBankKeeper. +type BankKeeperSendCoinsFromModuleToAccountFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 types.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 string + // Arg2 is the value of the 3rd argument passed to this method + // invocation. + Arg2 types.AccAddress + // Arg3 is the value of the 4th argument passed to this method + // invocation. + Arg3 types.Coins + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c BankKeeperSendCoinsFromModuleToAccountFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1, c.Arg2, c.Arg3} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c BankKeeperSendCoinsFromModuleToAccountFuncCall) Results() []interface{} { + return []interface{}{c.Result0} +} + +// MockLeverageKeeper is a mock implementation of the LeverageKeeper +// interface (from the package github.com/umee-network/umee/v5/x/metoken) +// used for unit testing. +type MockLeverageKeeper struct { + // ExchangeTokenFunc is an instance of a mock function object + // controlling the behavior of the method ExchangeToken. + ExchangeTokenFunc *LeverageKeeperExchangeTokenFunc + // ExchangeUTokenFunc is an instance of a mock function object + // controlling the behavior of the method ExchangeUToken. + ExchangeUTokenFunc *LeverageKeeperExchangeUTokenFunc + // GetTokenSettingsFunc is an instance of a mock function object + // controlling the behavior of the method GetTokenSettings. + GetTokenSettingsFunc *LeverageKeeperGetTokenSettingsFunc + // GetTotalSupplyFunc is an instance of a mock function object + // controlling the behavior of the method GetTotalSupply. + GetTotalSupplyFunc *LeverageKeeperGetTotalSupplyFunc + // ModuleMaxWithdrawFunc is an instance of a mock function object + // controlling the behavior of the method ModuleMaxWithdraw. + ModuleMaxWithdrawFunc *LeverageKeeperModuleMaxWithdrawFunc + // SupplyFunc is an instance of a mock function object controlling the + // behavior of the method Supply. + SupplyFunc *LeverageKeeperSupplyFunc + // WithdrawFunc is an instance of a mock function object controlling the + // behavior of the method Withdraw. + WithdrawFunc *LeverageKeeperWithdrawFunc +} + +// NewMockLeverageKeeper creates a new mock of the LeverageKeeper interface. +// All methods return zero values for all results, unless overwritten. +func NewMockLeverageKeeper() *MockLeverageKeeper { + return &MockLeverageKeeper{ + ExchangeTokenFunc: &LeverageKeeperExchangeTokenFunc{ + defaultHook: func(types.Context, types.Coin) (r0 types.Coin, r1 error) { + return + }, + }, + ExchangeUTokenFunc: &LeverageKeeperExchangeUTokenFunc{ + defaultHook: func(types.Context, types.Coin) (r0 types.Coin, r1 error) { + return + }, + }, + GetTokenSettingsFunc: &LeverageKeeperGetTokenSettingsFunc{ + defaultHook: func(types.Context, string) (r0 types1.Token, r1 error) { + return + }, + }, + GetTotalSupplyFunc: &LeverageKeeperGetTotalSupplyFunc{ + defaultHook: func(types.Context, string) (r0 types.Coin, r1 error) { + return + }, + }, + ModuleMaxWithdrawFunc: &LeverageKeeperModuleMaxWithdrawFunc{ + defaultHook: func(types.Context, types.Coin) (r0 math.Int, r1 error) { + return + }, + }, + SupplyFunc: &LeverageKeeperSupplyFunc{ + defaultHook: func(types.Context, types.AccAddress, types.Coin) (r0 types.Coin, r1 error) { + return + }, + }, + WithdrawFunc: &LeverageKeeperWithdrawFunc{ + defaultHook: func(types.Context, types.AccAddress, types.Coin) (r0 types.Coin, r1 bool, r2 error) { + return + }, + }, + } +} + +// NewStrictMockLeverageKeeper creates a new mock of the LeverageKeeper +// interface. All methods panic on invocation, unless overwritten. +func NewStrictMockLeverageKeeper() *MockLeverageKeeper { + return &MockLeverageKeeper{ + ExchangeTokenFunc: &LeverageKeeperExchangeTokenFunc{ + defaultHook: func(types.Context, types.Coin) (types.Coin, error) { + panic("unexpected invocation of MockLeverageKeeper.ExchangeToken") + }, + }, + ExchangeUTokenFunc: &LeverageKeeperExchangeUTokenFunc{ + defaultHook: func(types.Context, types.Coin) (types.Coin, error) { + panic("unexpected invocation of MockLeverageKeeper.ExchangeUToken") + }, + }, + GetTokenSettingsFunc: &LeverageKeeperGetTokenSettingsFunc{ + defaultHook: func(types.Context, string) (types1.Token, error) { + panic("unexpected invocation of MockLeverageKeeper.GetTokenSettings") + }, + }, + GetTotalSupplyFunc: &LeverageKeeperGetTotalSupplyFunc{ + defaultHook: func(types.Context, string) (types.Coin, error) { + panic("unexpected invocation of MockLeverageKeeper.GetTotalSupply") + }, + }, + ModuleMaxWithdrawFunc: &LeverageKeeperModuleMaxWithdrawFunc{ + defaultHook: func(types.Context, types.Coin) (math.Int, error) { + panic("unexpected invocation of MockLeverageKeeper.ModuleMaxWithdraw") + }, + }, + SupplyFunc: &LeverageKeeperSupplyFunc{ + defaultHook: func(types.Context, types.AccAddress, types.Coin) (types.Coin, error) { + panic("unexpected invocation of MockLeverageKeeper.Supply") + }, + }, + WithdrawFunc: &LeverageKeeperWithdrawFunc{ + defaultHook: func(types.Context, types.AccAddress, types.Coin) (types.Coin, bool, error) { + panic("unexpected invocation of MockLeverageKeeper.Withdraw") + }, + }, + } +} + +// NewMockLeverageKeeperFrom creates a new mock of the MockLeverageKeeper +// interface. All methods delegate to the given implementation, unless +// overwritten. +func NewMockLeverageKeeperFrom(i metoken.LeverageKeeper) *MockLeverageKeeper { + return &MockLeverageKeeper{ + ExchangeTokenFunc: &LeverageKeeperExchangeTokenFunc{ + defaultHook: i.ExchangeToken, + }, + ExchangeUTokenFunc: &LeverageKeeperExchangeUTokenFunc{ + defaultHook: i.ExchangeUToken, + }, + GetTokenSettingsFunc: &LeverageKeeperGetTokenSettingsFunc{ + defaultHook: i.GetTokenSettings, + }, + GetTotalSupplyFunc: &LeverageKeeperGetTotalSupplyFunc{ + defaultHook: i.GetTotalSupply, + }, + ModuleMaxWithdrawFunc: &LeverageKeeperModuleMaxWithdrawFunc{ + defaultHook: i.ModuleMaxWithdraw, + }, + SupplyFunc: &LeverageKeeperSupplyFunc{ + defaultHook: i.Supply, + }, + WithdrawFunc: &LeverageKeeperWithdrawFunc{ + defaultHook: i.Withdraw, + }, + } +} + +// LeverageKeeperExchangeTokenFunc describes the behavior when the +// ExchangeToken method of the parent MockLeverageKeeper instance is +// invoked. +type LeverageKeeperExchangeTokenFunc struct { + defaultHook func(types.Context, types.Coin) (types.Coin, error) + hooks []func(types.Context, types.Coin) (types.Coin, error) + history []LeverageKeeperExchangeTokenFuncCall + mutex sync.Mutex +} + +// ExchangeToken delegates to the next hook function in the queue and stores +// the parameter and result values of this invocation. +func (m *MockLeverageKeeper) ExchangeToken(v0 types.Context, v1 types.Coin) (types.Coin, error) { + r0, r1 := m.ExchangeTokenFunc.nextHook()(v0, v1) + m.ExchangeTokenFunc.appendCall(LeverageKeeperExchangeTokenFuncCall{v0, v1, r0, r1}) + return r0, r1 +} + +// SetDefaultHook sets function that is called when the ExchangeToken method +// of the parent MockLeverageKeeper instance is invoked and the hook queue +// is empty. +func (f *LeverageKeeperExchangeTokenFunc) SetDefaultHook(hook func(types.Context, types.Coin) (types.Coin, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// ExchangeToken method of the parent MockLeverageKeeper instance invokes +// the hook at the front of the queue and discards it. After the queue is +// empty, the default hook function is invoked for any future action. +func (f *LeverageKeeperExchangeTokenFunc) PushHook(hook func(types.Context, types.Coin) (types.Coin, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultHook with a function that returns the +// given values. +func (f *LeverageKeeperExchangeTokenFunc) SetDefaultReturn(r0 types.Coin, r1 error) { + f.SetDefaultHook(func(types.Context, types.Coin) (types.Coin, error) { + return r0, r1 + }) +} + +// PushReturn calls PushHook with a function that returns the given values. +func (f *LeverageKeeperExchangeTokenFunc) PushReturn(r0 types.Coin, r1 error) { + f.PushHook(func(types.Context, types.Coin) (types.Coin, error) { + return r0, r1 + }) +} + +func (f *LeverageKeeperExchangeTokenFunc) nextHook() func(types.Context, types.Coin) (types.Coin, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *LeverageKeeperExchangeTokenFunc) appendCall(r0 LeverageKeeperExchangeTokenFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of LeverageKeeperExchangeTokenFuncCall objects +// describing the invocations of this function. +func (f *LeverageKeeperExchangeTokenFunc) History() []LeverageKeeperExchangeTokenFuncCall { + f.mutex.Lock() + history := make([]LeverageKeeperExchangeTokenFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// LeverageKeeperExchangeTokenFuncCall is an object that describes an +// invocation of method ExchangeToken on an instance of MockLeverageKeeper. +type LeverageKeeperExchangeTokenFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 types.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 types.Coin + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 types.Coin + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c LeverageKeeperExchangeTokenFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c LeverageKeeperExchangeTokenFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1} +} + +// LeverageKeeperExchangeUTokenFunc describes the behavior when the +// ExchangeUToken method of the parent MockLeverageKeeper instance is +// invoked. +type LeverageKeeperExchangeUTokenFunc struct { + defaultHook func(types.Context, types.Coin) (types.Coin, error) + hooks []func(types.Context, types.Coin) (types.Coin, error) + history []LeverageKeeperExchangeUTokenFuncCall + mutex sync.Mutex +} + +// ExchangeUToken delegates to the next hook function in the queue and +// stores the parameter and result values of this invocation. +func (m *MockLeverageKeeper) ExchangeUToken(v0 types.Context, v1 types.Coin) (types.Coin, error) { + r0, r1 := m.ExchangeUTokenFunc.nextHook()(v0, v1) + m.ExchangeUTokenFunc.appendCall(LeverageKeeperExchangeUTokenFuncCall{v0, v1, r0, r1}) + return r0, r1 +} + +// SetDefaultHook sets function that is called when the ExchangeUToken +// method of the parent MockLeverageKeeper instance is invoked and the hook +// queue is empty. +func (f *LeverageKeeperExchangeUTokenFunc) SetDefaultHook(hook func(types.Context, types.Coin) (types.Coin, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// ExchangeUToken method of the parent MockLeverageKeeper instance invokes +// the hook at the front of the queue and discards it. After the queue is +// empty, the default hook function is invoked for any future action. +func (f *LeverageKeeperExchangeUTokenFunc) PushHook(hook func(types.Context, types.Coin) (types.Coin, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultHook with a function that returns the +// given values. +func (f *LeverageKeeperExchangeUTokenFunc) SetDefaultReturn(r0 types.Coin, r1 error) { + f.SetDefaultHook(func(types.Context, types.Coin) (types.Coin, error) { + return r0, r1 + }) +} + +// PushReturn calls PushHook with a function that returns the given values. +func (f *LeverageKeeperExchangeUTokenFunc) PushReturn(r0 types.Coin, r1 error) { + f.PushHook(func(types.Context, types.Coin) (types.Coin, error) { + return r0, r1 + }) +} + +func (f *LeverageKeeperExchangeUTokenFunc) nextHook() func(types.Context, types.Coin) (types.Coin, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *LeverageKeeperExchangeUTokenFunc) appendCall(r0 LeverageKeeperExchangeUTokenFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of LeverageKeeperExchangeUTokenFuncCall +// objects describing the invocations of this function. +func (f *LeverageKeeperExchangeUTokenFunc) History() []LeverageKeeperExchangeUTokenFuncCall { + f.mutex.Lock() + history := make([]LeverageKeeperExchangeUTokenFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// LeverageKeeperExchangeUTokenFuncCall is an object that describes an +// invocation of method ExchangeUToken on an instance of MockLeverageKeeper. +type LeverageKeeperExchangeUTokenFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 types.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 types.Coin + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 types.Coin + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c LeverageKeeperExchangeUTokenFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c LeverageKeeperExchangeUTokenFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1} +} + +// LeverageKeeperGetTokenSettingsFunc describes the behavior when the +// GetTokenSettings method of the parent MockLeverageKeeper instance is +// invoked. +type LeverageKeeperGetTokenSettingsFunc struct { + defaultHook func(types.Context, string) (types1.Token, error) + hooks []func(types.Context, string) (types1.Token, error) + history []LeverageKeeperGetTokenSettingsFuncCall + mutex sync.Mutex +} + +// GetTokenSettings delegates to the next hook function in the queue and +// stores the parameter and result values of this invocation. +func (m *MockLeverageKeeper) GetTokenSettings(v0 types.Context, v1 string) (types1.Token, error) { + r0, r1 := m.GetTokenSettingsFunc.nextHook()(v0, v1) + m.GetTokenSettingsFunc.appendCall(LeverageKeeperGetTokenSettingsFuncCall{v0, v1, r0, r1}) + return r0, r1 +} + +// SetDefaultHook sets function that is called when the GetTokenSettings +// method of the parent MockLeverageKeeper instance is invoked and the hook +// queue is empty. +func (f *LeverageKeeperGetTokenSettingsFunc) SetDefaultHook(hook func(types.Context, string) (types1.Token, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// GetTokenSettings method of the parent MockLeverageKeeper instance invokes +// the hook at the front of the queue and discards it. After the queue is +// empty, the default hook function is invoked for any future action. +func (f *LeverageKeeperGetTokenSettingsFunc) PushHook(hook func(types.Context, string) (types1.Token, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultHook with a function that returns the +// given values. +func (f *LeverageKeeperGetTokenSettingsFunc) SetDefaultReturn(r0 types1.Token, r1 error) { + f.SetDefaultHook(func(types.Context, string) (types1.Token, error) { + return r0, r1 + }) +} + +// PushReturn calls PushHook with a function that returns the given values. +func (f *LeverageKeeperGetTokenSettingsFunc) PushReturn(r0 types1.Token, r1 error) { + f.PushHook(func(types.Context, string) (types1.Token, error) { + return r0, r1 + }) +} + +func (f *LeverageKeeperGetTokenSettingsFunc) nextHook() func(types.Context, string) (types1.Token, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *LeverageKeeperGetTokenSettingsFunc) appendCall(r0 LeverageKeeperGetTokenSettingsFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of LeverageKeeperGetTokenSettingsFuncCall +// objects describing the invocations of this function. +func (f *LeverageKeeperGetTokenSettingsFunc) History() []LeverageKeeperGetTokenSettingsFuncCall { + f.mutex.Lock() + history := make([]LeverageKeeperGetTokenSettingsFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// LeverageKeeperGetTokenSettingsFuncCall is an object that describes an +// invocation of method GetTokenSettings on an instance of +// MockLeverageKeeper. +type LeverageKeeperGetTokenSettingsFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 types.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 string + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 types1.Token + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c LeverageKeeperGetTokenSettingsFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c LeverageKeeperGetTokenSettingsFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1} +} + +// LeverageKeeperGetTotalSupplyFunc describes the behavior when the +// GetTotalSupply method of the parent MockLeverageKeeper instance is +// invoked. +type LeverageKeeperGetTotalSupplyFunc struct { + defaultHook func(types.Context, string) (types.Coin, error) + hooks []func(types.Context, string) (types.Coin, error) + history []LeverageKeeperGetTotalSupplyFuncCall + mutex sync.Mutex +} + +// GetTotalSupply delegates to the next hook function in the queue and +// stores the parameter and result values of this invocation. +func (m *MockLeverageKeeper) GetTotalSupply(v0 types.Context, v1 string) (types.Coin, error) { + r0, r1 := m.GetTotalSupplyFunc.nextHook()(v0, v1) + m.GetTotalSupplyFunc.appendCall(LeverageKeeperGetTotalSupplyFuncCall{v0, v1, r0, r1}) + return r0, r1 +} + +// SetDefaultHook sets function that is called when the GetTotalSupply +// method of the parent MockLeverageKeeper instance is invoked and the hook +// queue is empty. +func (f *LeverageKeeperGetTotalSupplyFunc) SetDefaultHook(hook func(types.Context, string) (types.Coin, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// GetTotalSupply method of the parent MockLeverageKeeper instance invokes +// the hook at the front of the queue and discards it. After the queue is +// empty, the default hook function is invoked for any future action. +func (f *LeverageKeeperGetTotalSupplyFunc) PushHook(hook func(types.Context, string) (types.Coin, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultHook with a function that returns the +// given values. +func (f *LeverageKeeperGetTotalSupplyFunc) SetDefaultReturn(r0 types.Coin, r1 error) { + f.SetDefaultHook(func(types.Context, string) (types.Coin, error) { + return r0, r1 + }) +} + +// PushReturn calls PushHook with a function that returns the given values. +func (f *LeverageKeeperGetTotalSupplyFunc) PushReturn(r0 types.Coin, r1 error) { + f.PushHook(func(types.Context, string) (types.Coin, error) { + return r0, r1 + }) +} + +func (f *LeverageKeeperGetTotalSupplyFunc) nextHook() func(types.Context, string) (types.Coin, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *LeverageKeeperGetTotalSupplyFunc) appendCall(r0 LeverageKeeperGetTotalSupplyFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of LeverageKeeperGetTotalSupplyFuncCall +// objects describing the invocations of this function. +func (f *LeverageKeeperGetTotalSupplyFunc) History() []LeverageKeeperGetTotalSupplyFuncCall { + f.mutex.Lock() + history := make([]LeverageKeeperGetTotalSupplyFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// LeverageKeeperGetTotalSupplyFuncCall is an object that describes an +// invocation of method GetTotalSupply on an instance of MockLeverageKeeper. +type LeverageKeeperGetTotalSupplyFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 types.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 string + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 types.Coin + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c LeverageKeeperGetTotalSupplyFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c LeverageKeeperGetTotalSupplyFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1} +} + +// LeverageKeeperModuleMaxWithdrawFunc describes the behavior when the +// ModuleMaxWithdraw method of the parent MockLeverageKeeper instance is +// invoked. +type LeverageKeeperModuleMaxWithdrawFunc struct { + defaultHook func(types.Context, types.Coin) (math.Int, error) + hooks []func(types.Context, types.Coin) (math.Int, error) + history []LeverageKeeperModuleMaxWithdrawFuncCall + mutex sync.Mutex +} + +// ModuleMaxWithdraw delegates to the next hook function in the queue and +// stores the parameter and result values of this invocation. +func (m *MockLeverageKeeper) ModuleMaxWithdraw(v0 types.Context, v1 types.Coin) (math.Int, error) { + r0, r1 := m.ModuleMaxWithdrawFunc.nextHook()(v0, v1) + m.ModuleMaxWithdrawFunc.appendCall(LeverageKeeperModuleMaxWithdrawFuncCall{v0, v1, r0, r1}) + return r0, r1 +} + +// SetDefaultHook sets function that is called when the ModuleMaxWithdraw +// method of the parent MockLeverageKeeper instance is invoked and the hook +// queue is empty. +func (f *LeverageKeeperModuleMaxWithdrawFunc) SetDefaultHook(hook func(types.Context, types.Coin) (math.Int, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// ModuleMaxWithdraw method of the parent MockLeverageKeeper instance +// invokes the hook at the front of the queue and discards it. After the +// queue is empty, the default hook function is invoked for any future +// action. +func (f *LeverageKeeperModuleMaxWithdrawFunc) PushHook(hook func(types.Context, types.Coin) (math.Int, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultHook with a function that returns the +// given values. +func (f *LeverageKeeperModuleMaxWithdrawFunc) SetDefaultReturn(r0 math.Int, r1 error) { + f.SetDefaultHook(func(types.Context, types.Coin) (math.Int, error) { + return r0, r1 + }) +} + +// PushReturn calls PushHook with a function that returns the given values. +func (f *LeverageKeeperModuleMaxWithdrawFunc) PushReturn(r0 math.Int, r1 error) { + f.PushHook(func(types.Context, types.Coin) (math.Int, error) { + return r0, r1 + }) +} + +func (f *LeverageKeeperModuleMaxWithdrawFunc) nextHook() func(types.Context, types.Coin) (math.Int, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *LeverageKeeperModuleMaxWithdrawFunc) appendCall(r0 LeverageKeeperModuleMaxWithdrawFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of LeverageKeeperModuleMaxWithdrawFuncCall +// objects describing the invocations of this function. +func (f *LeverageKeeperModuleMaxWithdrawFunc) History() []LeverageKeeperModuleMaxWithdrawFuncCall { + f.mutex.Lock() + history := make([]LeverageKeeperModuleMaxWithdrawFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// LeverageKeeperModuleMaxWithdrawFuncCall is an object that describes an +// invocation of method ModuleMaxWithdraw on an instance of +// MockLeverageKeeper. +type LeverageKeeperModuleMaxWithdrawFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 types.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 types.Coin + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 math.Int + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c LeverageKeeperModuleMaxWithdrawFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c LeverageKeeperModuleMaxWithdrawFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1} +} + +// LeverageKeeperSupplyFunc describes the behavior when the Supply method of +// the parent MockLeverageKeeper instance is invoked. +type LeverageKeeperSupplyFunc struct { + defaultHook func(types.Context, types.AccAddress, types.Coin) (types.Coin, error) + hooks []func(types.Context, types.AccAddress, types.Coin) (types.Coin, error) + history []LeverageKeeperSupplyFuncCall + mutex sync.Mutex +} + +// Supply delegates to the next hook function in the queue and stores the +// parameter and result values of this invocation. +func (m *MockLeverageKeeper) Supply(v0 types.Context, v1 types.AccAddress, v2 types.Coin) (types.Coin, error) { + r0, r1 := m.SupplyFunc.nextHook()(v0, v1, v2) + m.SupplyFunc.appendCall(LeverageKeeperSupplyFuncCall{v0, v1, v2, r0, r1}) + return r0, r1 +} + +// SetDefaultHook sets function that is called when the Supply method of the +// parent MockLeverageKeeper instance is invoked and the hook queue is +// empty. +func (f *LeverageKeeperSupplyFunc) SetDefaultHook(hook func(types.Context, types.AccAddress, types.Coin) (types.Coin, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// Supply method of the parent MockLeverageKeeper instance invokes the hook +// at the front of the queue and discards it. After the queue is empty, the +// default hook function is invoked for any future action. +func (f *LeverageKeeperSupplyFunc) PushHook(hook func(types.Context, types.AccAddress, types.Coin) (types.Coin, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultHook with a function that returns the +// given values. +func (f *LeverageKeeperSupplyFunc) SetDefaultReturn(r0 types.Coin, r1 error) { + f.SetDefaultHook(func(types.Context, types.AccAddress, types.Coin) (types.Coin, error) { + return r0, r1 + }) +} + +// PushReturn calls PushHook with a function that returns the given values. +func (f *LeverageKeeperSupplyFunc) PushReturn(r0 types.Coin, r1 error) { + f.PushHook(func(types.Context, types.AccAddress, types.Coin) (types.Coin, error) { + return r0, r1 + }) +} + +func (f *LeverageKeeperSupplyFunc) nextHook() func(types.Context, types.AccAddress, types.Coin) (types.Coin, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *LeverageKeeperSupplyFunc) appendCall(r0 LeverageKeeperSupplyFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of LeverageKeeperSupplyFuncCall objects +// describing the invocations of this function. +func (f *LeverageKeeperSupplyFunc) History() []LeverageKeeperSupplyFuncCall { + f.mutex.Lock() + history := make([]LeverageKeeperSupplyFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// LeverageKeeperSupplyFuncCall is an object that describes an invocation of +// method Supply on an instance of MockLeverageKeeper. +type LeverageKeeperSupplyFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 types.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 types.AccAddress + // Arg2 is the value of the 3rd argument passed to this method + // invocation. + Arg2 types.Coin + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 types.Coin + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c LeverageKeeperSupplyFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1, c.Arg2} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c LeverageKeeperSupplyFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1} +} + +// LeverageKeeperWithdrawFunc describes the behavior when the Withdraw +// method of the parent MockLeverageKeeper instance is invoked. +type LeverageKeeperWithdrawFunc struct { + defaultHook func(types.Context, types.AccAddress, types.Coin) (types.Coin, bool, error) + hooks []func(types.Context, types.AccAddress, types.Coin) (types.Coin, bool, error) + history []LeverageKeeperWithdrawFuncCall + mutex sync.Mutex +} + +// Withdraw delegates to the next hook function in the queue and stores the +// parameter and result values of this invocation. +func (m *MockLeverageKeeper) Withdraw(v0 types.Context, v1 types.AccAddress, v2 types.Coin) (types.Coin, bool, error) { + r0, r1, r2 := m.WithdrawFunc.nextHook()(v0, v1, v2) + m.WithdrawFunc.appendCall(LeverageKeeperWithdrawFuncCall{v0, v1, v2, r0, r1, r2}) + return r0, r1, r2 +} + +// SetDefaultHook sets function that is called when the Withdraw method of +// the parent MockLeverageKeeper instance is invoked and the hook queue is +// empty. +func (f *LeverageKeeperWithdrawFunc) SetDefaultHook(hook func(types.Context, types.AccAddress, types.Coin) (types.Coin, bool, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// Withdraw method of the parent MockLeverageKeeper instance invokes the +// hook at the front of the queue and discards it. After the queue is empty, +// the default hook function is invoked for any future action. +func (f *LeverageKeeperWithdrawFunc) PushHook(hook func(types.Context, types.AccAddress, types.Coin) (types.Coin, bool, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultHook with a function that returns the +// given values. +func (f *LeverageKeeperWithdrawFunc) SetDefaultReturn(r0 types.Coin, r1 bool, r2 error) { + f.SetDefaultHook(func(types.Context, types.AccAddress, types.Coin) (types.Coin, bool, error) { + return r0, r1, r2 + }) +} + +// PushReturn calls PushHook with a function that returns the given values. +func (f *LeverageKeeperWithdrawFunc) PushReturn(r0 types.Coin, r1 bool, r2 error) { + f.PushHook(func(types.Context, types.AccAddress, types.Coin) (types.Coin, bool, error) { + return r0, r1, r2 + }) +} + +func (f *LeverageKeeperWithdrawFunc) nextHook() func(types.Context, types.AccAddress, types.Coin) (types.Coin, bool, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *LeverageKeeperWithdrawFunc) appendCall(r0 LeverageKeeperWithdrawFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of LeverageKeeperWithdrawFuncCall objects +// describing the invocations of this function. +func (f *LeverageKeeperWithdrawFunc) History() []LeverageKeeperWithdrawFuncCall { + f.mutex.Lock() + history := make([]LeverageKeeperWithdrawFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// LeverageKeeperWithdrawFuncCall is an object that describes an invocation +// of method Withdraw on an instance of MockLeverageKeeper. +type LeverageKeeperWithdrawFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 types.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 types.AccAddress + // Arg2 is the value of the 3rd argument passed to this method + // invocation. + Arg2 types.Coin + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 types.Coin + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 bool + // Result2 is the value of the 3rd result returned from this method + // invocation. + Result2 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c LeverageKeeperWithdrawFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1, c.Arg2} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c LeverageKeeperWithdrawFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1, c.Result2} +} + +// MockOracleKeeper is a mock implementation of the OracleKeeper interface +// (from the package github.com/umee-network/umee/v5/x/metoken) used for +// unit testing. +type MockOracleKeeper struct { + // AllMedianPricesFunc is an instance of a mock function object + // controlling the behavior of the method AllMedianPrices. + AllMedianPricesFunc *OracleKeeperAllMedianPricesFunc +} + +// NewMockOracleKeeper creates a new mock of the OracleKeeper interface. All +// methods return zero values for all results, unless overwritten. +func NewMockOracleKeeper() *MockOracleKeeper { + return &MockOracleKeeper{ + AllMedianPricesFunc: &OracleKeeperAllMedianPricesFunc{ + defaultHook: func(types.Context) (r0 types2.Prices) { + return + }, + }, + } +} + +// NewStrictMockOracleKeeper creates a new mock of the OracleKeeper +// interface. All methods panic on invocation, unless overwritten. +func NewStrictMockOracleKeeper() *MockOracleKeeper { + return &MockOracleKeeper{ + AllMedianPricesFunc: &OracleKeeperAllMedianPricesFunc{ + defaultHook: func(types.Context) types2.Prices { + panic("unexpected invocation of MockOracleKeeper.AllMedianPrices") + }, + }, + } +} + +// NewMockOracleKeeperFrom creates a new mock of the MockOracleKeeper +// interface. All methods delegate to the given implementation, unless +// overwritten. +func NewMockOracleKeeperFrom(i metoken.OracleKeeper) *MockOracleKeeper { + return &MockOracleKeeper{ + AllMedianPricesFunc: &OracleKeeperAllMedianPricesFunc{ + defaultHook: i.AllMedianPrices, + }, + } +} + +// OracleKeeperAllMedianPricesFunc describes the behavior when the +// AllMedianPrices method of the parent MockOracleKeeper instance is +// invoked. +type OracleKeeperAllMedianPricesFunc struct { + defaultHook func(types.Context) types2.Prices + hooks []func(types.Context) types2.Prices + history []OracleKeeperAllMedianPricesFuncCall + mutex sync.Mutex +} + +// AllMedianPrices delegates to the next hook function in the queue and +// stores the parameter and result values of this invocation. +func (m *MockOracleKeeper) AllMedianPrices(v0 types.Context) types2.Prices { + r0 := m.AllMedianPricesFunc.nextHook()(v0) + m.AllMedianPricesFunc.appendCall(OracleKeeperAllMedianPricesFuncCall{v0, r0}) + return r0 +} + +// SetDefaultHook sets function that is called when the AllMedianPrices +// method of the parent MockOracleKeeper instance is invoked and the hook +// queue is empty. +func (f *OracleKeeperAllMedianPricesFunc) SetDefaultHook(hook func(types.Context) types2.Prices) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// AllMedianPrices method of the parent MockOracleKeeper instance invokes +// the hook at the front of the queue and discards it. After the queue is +// empty, the default hook function is invoked for any future action. +func (f *OracleKeeperAllMedianPricesFunc) PushHook(hook func(types.Context) types2.Prices) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultHook with a function that returns the +// given values. +func (f *OracleKeeperAllMedianPricesFunc) SetDefaultReturn(r0 types2.Prices) { + f.SetDefaultHook(func(types.Context) types2.Prices { + return r0 + }) +} + +// PushReturn calls PushHook with a function that returns the given values. +func (f *OracleKeeperAllMedianPricesFunc) PushReturn(r0 types2.Prices) { + f.PushHook(func(types.Context) types2.Prices { + return r0 + }) +} + +func (f *OracleKeeperAllMedianPricesFunc) nextHook() func(types.Context) types2.Prices { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *OracleKeeperAllMedianPricesFunc) appendCall(r0 OracleKeeperAllMedianPricesFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of OracleKeeperAllMedianPricesFuncCall objects +// describing the invocations of this function. +func (f *OracleKeeperAllMedianPricesFunc) History() []OracleKeeperAllMedianPricesFuncCall { + f.mutex.Lock() + history := make([]OracleKeeperAllMedianPricesFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// OracleKeeperAllMedianPricesFuncCall is an object that describes an +// invocation of method AllMedianPrices on an instance of MockOracleKeeper. +type OracleKeeperAllMedianPricesFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 types.Context + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 types2.Prices +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c OracleKeeperAllMedianPricesFuncCall) Args() []interface{} { + return []interface{}{c.Arg0} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c OracleKeeperAllMedianPricesFuncCall) Results() []interface{} { + return []interface{}{c.Result0} +} diff --git a/x/metoken/mocks/metoken.go b/x/metoken/mocks/metoken.go new file mode 100644 index 0000000000..c30ba50296 --- /dev/null +++ b/x/metoken/mocks/metoken.go @@ -0,0 +1,198 @@ +package mocks + +import ( + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + + ltypes "github.com/umee-network/umee/v5/x/leverage/types" + "github.com/umee-network/umee/v5/x/metoken" + otypes "github.com/umee-network/umee/v5/x/oracle/types" +) + +const ( + USDTBaseDenom = "ibc/223420B0E8CF9CC47BCAB816AB3A20AE162EED27C1177F4B2BC270C83E11AD8D" + USDTSymbolDenom = "USDT" + USDCBaseDenom = "ibc/49788C29CD84E08D25CA7BE960BC1F61E88FEFC6333F58557D236D693398466A" + USDCSymbolDenom = "USDC" + ISTBaseDenom = "ibc/BA460328D9ABA27E643A924071FDB3836E4CE8084C6D2380F25EFAB85CF8EB11" + ISTSymbolDenom = "IST" + WBTCBaseDenom = "ibc/153B97FE395140EAAA2D7CAC537AF1804AEC5F0595CBC5F1603094018D158C0C" + WBTCSymbolDenom = "WBTC" + ETHBaseDenom = "ibc/04CE51E6E02243E565AE676DD60336E48D455F8AAD0611FA0299A22FDAC448D6" + ETHSymbolDenom = "ETH" + MeUSDDenom = "me/USD" + MeNonStableDenom = "me/NonStable" +) + +var ( + USDTPrice = sdk.MustNewDecFromStr("0.998") + USDCPrice = sdk.MustNewDecFromStr("1.0") + ISTPrice = sdk.MustNewDecFromStr("1.02") + WBTCPrice = sdk.MustNewDecFromStr("27268.938478585498709550") + ETHPrice = sdk.MustNewDecFromStr("1851.789229542837161069") +) + +func StableIndex(denom string) metoken.Index { + return metoken.NewIndex( + denom, + sdkmath.NewInt(1_000_000_000_000), + 6, + ValidFee(), + []metoken.AcceptedAsset{ + acceptedAsset(USDTBaseDenom, "0.33"), + acceptedAsset(USDCBaseDenom, "0.34"), + acceptedAsset(ISTBaseDenom, "0.33"), + }, + ) +} + +func NonStableIndex(denom string) metoken.Index { + return metoken.NewIndex( + denom, + sdkmath.NewInt(1_000_000_000_000), + 8, + ValidFee(), + []metoken.AcceptedAsset{ + acceptedAsset(USDTBaseDenom, "0.33"), + acceptedAsset(WBTCBaseDenom, "0.34"), + acceptedAsset(ETHBaseDenom, "0.33"), + }, + ) +} + +func acceptedAsset(denom, targetAllocation string) metoken.AcceptedAsset { + return metoken.NewAcceptedAsset(denom, sdk.MustNewDecFromStr("0.2"), sdk.MustNewDecFromStr(targetAllocation)) +} + +func ValidFee() metoken.Fee { + return metoken.NewFee( + sdk.MustNewDecFromStr("0.01"), + sdk.MustNewDecFromStr("0.2"), + sdk.MustNewDecFromStr("0.5"), + ) +} + +func EmptyUSDIndexBalances(denom string) metoken.IndexBalances { + return metoken.NewIndexBalances( + sdk.NewCoin(denom, sdkmath.ZeroInt()), + []metoken.AssetBalance{ + metoken.NewZeroAssetBalance(USDTBaseDenom), + metoken.NewZeroAssetBalance(USDCBaseDenom), + metoken.NewZeroAssetBalance(ISTBaseDenom), + }, + ) +} + +func ValidUSDIndexBalances(denom string) metoken.IndexBalances { + return metoken.NewIndexBalances( + sdk.NewCoin(denom, sdkmath.NewInt(4960_000000)), + []metoken.AssetBalance{ + metoken.NewAssetBalance( + USDTBaseDenom, + sdkmath.NewInt(960_000000), + sdkmath.NewInt(240_000000), + sdkmath.NewInt(34_000000), + sdkmath.ZeroInt(), + ), + metoken.NewAssetBalance( + USDCBaseDenom, + sdkmath.NewInt(608_000000), + sdkmath.NewInt(152_000000), + sdkmath.NewInt(28_000000), + sdkmath.ZeroInt(), + ), + metoken.NewAssetBalance( + ISTBaseDenom, + sdkmath.NewInt(2400_000000), + sdkmath.NewInt(600_000000), + sdkmath.NewInt(76_000000), + sdkmath.ZeroInt(), + ), + }, + ) +} + +// ValidPrices return 24 medians, each one with different prices +func ValidPrices() otypes.Prices { + prices := otypes.Prices{} + usdtPrice := USDTPrice.Sub(sdk.MustNewDecFromStr("0.24")) + usdcPrice := USDCPrice.Sub(sdk.MustNewDecFromStr("0.24")) + istPrice := ISTPrice.Sub(sdk.MustNewDecFromStr("0.24")) + wbtcPrice := WBTCPrice.Sub(sdk.MustNewDecFromStr("0.24")) + ethPrice := ETHPrice.Sub(sdk.MustNewDecFromStr("0.24")) + for i := 1; i <= 24; i++ { + median := otypes.Price{ + ExchangeRateTuple: otypes.NewExchangeRateTuple( + USDTSymbolDenom, + usdtPrice.Add(sdk.MustNewDecFromStr("0.01").MulInt(sdkmath.NewInt(int64(i)))), + ), + BlockNum: uint64(i), + } + prices = append(prices, median) + median = otypes.Price{ + ExchangeRateTuple: otypes.NewExchangeRateTuple( + USDCSymbolDenom, + usdcPrice.Add(sdk.MustNewDecFromStr("0.01").MulInt(sdkmath.NewInt(int64(i)))), + ), + BlockNum: uint64(i), + } + prices = append(prices, median) + median = otypes.Price{ + ExchangeRateTuple: otypes.NewExchangeRateTuple( + ISTSymbolDenom, + istPrice.Add(sdk.MustNewDecFromStr("0.01").MulInt(sdkmath.NewInt(int64(i)))), + ), + BlockNum: uint64(i), + } + prices = append(prices, median) + median = otypes.Price{ + ExchangeRateTuple: otypes.NewExchangeRateTuple( + WBTCSymbolDenom, + wbtcPrice.Add(sdk.MustNewDecFromStr("0.01").MulInt(sdkmath.NewInt(int64(i)))), + ), + BlockNum: uint64(i), + } + prices = append(prices, median) + median = otypes.Price{ + ExchangeRateTuple: otypes.NewExchangeRateTuple( + ETHSymbolDenom, + ethPrice.Add(sdk.MustNewDecFromStr("0.01").MulInt(sdkmath.NewInt(int64(i)))), + ), + BlockNum: uint64(i), + } + prices = append(prices, median) + } + + return prices +} + +// ValidPricesFunc return mock func for x/oracle +func ValidPricesFunc() func(ctx sdk.Context) otypes.Prices { + return func(ctx sdk.Context) otypes.Prices { + return ValidPrices() + } +} + +func ValidToken(baseDenom, symbolDenom string, exponent uint32) ltypes.Token { + return ltypes.Token{ + BaseDenom: baseDenom, + SymbolDenom: symbolDenom, + Exponent: exponent, + ReserveFactor: sdk.MustNewDecFromStr("0.25"), + CollateralWeight: sdk.MustNewDecFromStr("0.5"), + LiquidationThreshold: sdk.MustNewDecFromStr("0.51"), + BaseBorrowRate: sdk.MustNewDecFromStr("0.01"), + KinkBorrowRate: sdk.MustNewDecFromStr("0.05"), + MaxBorrowRate: sdk.MustNewDecFromStr("1"), + KinkUtilization: sdk.MustNewDecFromStr("0.75"), + LiquidationIncentive: sdk.MustNewDecFromStr("0.05"), + EnableMsgSupply: true, + EnableMsgBorrow: true, + Blacklist: false, + MaxCollateralShare: sdk.MustNewDecFromStr("1"), + MaxSupplyUtilization: sdk.MustNewDecFromStr("1"), + MinCollateralLiquidity: sdk.MustNewDecFromStr("1"), + MaxSupply: sdk.ZeroInt(), + HistoricMedians: 24, + } +} diff --git a/x/metoken/module/abci.go b/x/metoken/module/abci.go new file mode 100644 index 0000000000..e7a251b7a7 --- /dev/null +++ b/x/metoken/module/abci.go @@ -0,0 +1,13 @@ +package module + +import ( + abci "github.com/tendermint/tendermint/abci/types" + "github.com/umee-network/umee/v5/x/metoken/keeper" +) + +// EndBlocker implements EndBlock for the x/metoken module. +func EndBlocker(_ keeper.Keeper) []abci.ValidatorUpdate { + // todo: add reserves re-balancing + // todo: add interest claiming + return []abci.ValidatorUpdate{} +} diff --git a/x/metoken/module/module.go b/x/metoken/module/module.go new file mode 100644 index 0000000000..9adc5b59a2 --- /dev/null +++ b/x/metoken/module/module.go @@ -0,0 +1,139 @@ +package module + +import ( + "context" + "encoding/json" + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/umee-network/umee/v5/x/metoken/client/cli" + + "github.com/umee-network/umee/v5/util" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/types/module" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/spf13/cobra" + "github.com/umee-network/umee/v5/x/metoken" + "github.com/umee-network/umee/v5/x/metoken/keeper" +) + +var ( + _ module.AppModule = AppModule{} + _ module.AppModuleBasic = AppModuleBasic{} +) + +// AppModuleBasic implements the AppModuleBasic interface for the x/metoken module. +type AppModuleBasic struct { + cdc codec.Codec +} + +// Name implements module.AppModuleBasic +func (AppModuleBasic) Name() string { + return metoken.ModuleName +} + +// RegisterLegacyAminoCodec implements module.AppModuleBasic +func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + metoken.RegisterLegacyAminoCodec(cdc) +} + +// RegisterInterfaces implements module.AppModuleBasic +func (AppModuleBasic) RegisterInterfaces(registry types.InterfaceRegistry) { + metoken.RegisterInterfaces(registry) +} + +// DefaultGenesis implements module.AppModuleBasic +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + return cdc.MustMarshalJSON(metoken.DefaultGenesisState()) +} + +// ValidateGenesis implements module.AppModuleBasic +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, _ client.TxEncodingConfig, bz json.RawMessage) error { + var gs metoken.GenesisState + if err := cdc.UnmarshalJSON(bz, &gs); err != nil { + return fmt.Errorf("failed to unmarshal %s genesis state: %w", metoken.ModuleName, err) + } + + return gs.Validate() +} + +// RegisterGRPCGatewayRoutes implements module.AppModuleBasic +func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { + err := metoken.RegisterQueryHandlerClient(context.Background(), mux, metoken.NewQueryClient(clientCtx)) + util.Panic(err) +} + +// GetTxCmd implements module.AppModuleBasic +func (AppModuleBasic) GetTxCmd() *cobra.Command { + return cli.GetTxCmd() +} + +// GetQueryCmd implements module.AppModuleBasic +func (AppModuleBasic) GetQueryCmd() *cobra.Command { + return cli.GetQueryCmd() +} + +func NewAppModuleBasic(cdc codec.Codec) AppModuleBasic { + return AppModuleBasic{cdc: cdc} +} + +// AppModule represents the AppModule for this module +type AppModule struct { + AppModuleBasic + kb keeper.Builder +} + +// InitGenesis implements module.AppModule +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate { + var genState metoken.GenesisState + cdc.MustUnmarshalJSON(data, &genState) + am.kb.Keeper(&ctx).InitGenesis(genState) + + return []abci.ValidatorUpdate{} +} + +// ExportGenesis implements module.AppModule +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { + genState := am.kb.Keeper(&ctx).ExportGenesis() + return cdc.MustMarshalJSON(genState) +} + +// RegisterInvariants implements module.AppModule +func (am AppModule) RegisterInvariants(sdk.InvariantRegistry) {} + +// RegisterServices implements module.AppModule +func (am AppModule) RegisterServices(cfg module.Configurator) { + metoken.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.kb)) + metoken.RegisterQueryServer(cfg.QueryServer(), keeper.NewQuerier(am.kb)) +} + +// ConsensusVersion implements module.AppModule +func (am AppModule) ConsensusVersion() uint64 { + return 1 +} + +// BeginBlock executes all ABCI BeginBlock logic respective to the x/metoken module. +func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {} + +// EndBlock executes all ABCI EndBlock logic respective to the x/metoken module. +// It returns no validator updates. +func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { + return EndBlocker(am.kb.Keeper(&ctx)) +} + +func NewAppModule(cdc codec.Codec, kb keeper.Builder) AppModule { + return AppModule{ + AppModuleBasic: NewAppModuleBasic(cdc), + kb: kb, + } +} + +// DEPRECATED + +func (AppModule) LegacyQuerierHandler(*codec.LegacyAmino) sdk.Querier { return nil } +func (AppModule) QuerierRoute() string { return "" } +func (AppModule) Route() sdk.Route { return sdk.Route{} } diff --git a/x/metoken/msgs.go b/x/metoken/msgs.go new file mode 100644 index 0000000000..4b227bd0dd --- /dev/null +++ b/x/metoken/msgs.go @@ -0,0 +1,181 @@ +package metoken + +import ( + "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/umee-network/umee/v5/util/checkers" +) + +var ( + _ sdk.Msg = &MsgSwap{} + _ sdk.Msg = &MsgRedeem{} + _ sdk.Msg = &MsgGovSetParams{} + _ sdk.Msg = &MsgGovUpdateRegistry{} +) + +func NewMsgSwap(user sdk.AccAddress, asset sdk.Coin, metokenDenom string) *MsgSwap { + return &MsgSwap{ + User: user.String(), + Asset: asset, + MetokenDenom: metokenDenom, + } +} + +// ValidateBasic implements Msg +func (msg *MsgSwap) ValidateBasic() error { + return validateUserAndAssetAndDenom(msg.User, &msg.Asset, msg.MetokenDenom) +} + +// GetSigners implements Msg +func (msg *MsgSwap) GetSigners() []sdk.AccAddress { + return checkers.Signers(msg.User) +} + +// LegacyMsg.Type implementations +func (msg MsgSwap) Route() string { return "" } + +func (msg MsgSwap) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&msg)) +} +func (msg MsgSwap) Type() string { return sdk.MsgTypeURL(&msg) } + +func NewMsgRedeem(user sdk.AccAddress, metoken sdk.Coin, assetDenom string) *MsgRedeem { + return &MsgRedeem{ + User: user.String(), + Metoken: metoken, + AssetDenom: assetDenom, + } +} + +// ValidateBasic implements Msg +func (msg *MsgRedeem) ValidateBasic() error { + return validateUserAndAssetAndDenom(msg.User, &msg.Metoken, msg.AssetDenom) +} + +// GetSigners implements Msg +func (msg *MsgRedeem) GetSigners() []sdk.AccAddress { + return checkers.Signers(msg.User) +} + +// LegacyMsg.Type implementations +func (msg MsgRedeem) Route() string { return "" } + +func (msg MsgRedeem) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&msg)) +} +func (msg MsgRedeem) Type() string { return sdk.MsgTypeURL(&msg) } + +func NewMsgGovSetParams(authority string, params Params) *MsgGovSetParams { + return &MsgGovSetParams{ + Authority: authority, + Params: params, + } +} + +// ValidateBasic implements Msg +func (msg *MsgGovSetParams) ValidateBasic() error { + return checkers.IsGovAuthority(msg.Authority) +} + +// GetSigners implements Msg +func (msg *MsgGovSetParams) GetSigners() []sdk.AccAddress { + return checkers.Signers(msg.Authority) +} + +// LegacyMsg.Type implementations +func (msg MsgGovSetParams) Route() string { return "" } + +func (msg MsgGovSetParams) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&msg)) +} +func (msg MsgGovSetParams) Type() string { return sdk.MsgTypeURL(&msg) } + +func NewMsgGovUpdateRegistry(authority string, addIndex, updateIndex []Index) *MsgGovUpdateRegistry { + return &MsgGovUpdateRegistry{ + Authority: authority, + AddIndex: addIndex, + UpdateIndex: updateIndex, + } +} + +// ValidateBasic implements Msg +func (msg *MsgGovUpdateRegistry) ValidateBasic() error { + if err := checkers.IsGovAuthority(msg.Authority); err != nil { + return err + } + + if len(msg.AddIndex) == 0 && len(msg.UpdateIndex) == 0 { + return sdkerrors.ErrInvalidRequest.Wrap("empty add and update indexes") + } + + if err := validateDuplicates(msg.AddIndex, msg.UpdateIndex); err != nil { + return err + } + + for _, index := range msg.AddIndex { + if err := index.Validate(); err != nil { + return errors.Wrapf(err, "addIndex: %s", index.Denom) + } + } + + for _, index := range msg.UpdateIndex { + if err := index.Validate(); err != nil { + return errors.Wrapf(err, "updateIndex: %s", index.Denom) + } + } + + return nil +} + +// GetSigners implements Msg +func (msg *MsgGovUpdateRegistry) GetSigners() []sdk.AccAddress { + return checkers.Signers(msg.Authority) +} + +// LegacyMsg.Type implementations +func (msg MsgGovUpdateRegistry) Route() string { return "" } + +func (msg MsgGovUpdateRegistry) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&msg)) +} +func (msg MsgGovUpdateRegistry) Type() string { return sdk.MsgTypeURL(&msg) } + +func validateUserAndAssetAndDenom(sender string, asset *sdk.Coin, denom string) error { + if _, err := sdk.AccAddressFromBech32(sender); err != nil { + return err + } + if asset == nil { + return sdkerrors.ErrInvalidRequest.Wrap("nil asset") + } + if err := asset.Validate(); err != nil { + return err + } + + return sdk.ValidateDenom(denom) +} + +func validateDuplicates(addIndex, updateIndex []Index) error { + indexes := make(map[string]struct{}) + for _, index := range addIndex { + if _, ok := indexes[index.Denom]; ok { + return sdkerrors.ErrInvalidRequest.Wrapf( + "duplicate addIndex metoken denom %s", + index.Denom, + ) + } + indexes[index.Denom] = struct{}{} + } + + for _, index := range updateIndex { + if _, ok := indexes[index.Denom]; ok { + return sdkerrors.ErrInvalidRequest.Wrapf( + "duplicate updateIndex metoken denom %s", + index.Denom, + ) + } + indexes[index.Denom] = struct{}{} + } + + return nil +} diff --git a/x/metoken/params.go b/x/metoken/params.go new file mode 100644 index 0000000000..3cab5ed3b6 --- /dev/null +++ b/x/metoken/params.go @@ -0,0 +1,9 @@ +package metoken + +// DefaultParams returns default genesis params +func DefaultParams() Params { + return Params{ + RebalancingFrequency: 60 * 60 * 12, // 12h + ClaimingFrequency: 60 * 60 * 24 * 7, // 7d + } +} diff --git a/x/metoken/params_test.go b/x/metoken/params_test.go new file mode 100644 index 0000000000..d9c09e907e --- /dev/null +++ b/x/metoken/params_test.go @@ -0,0 +1,13 @@ +package metoken + +import ( + "testing" + + "gotest.tools/v3/assert" +) + +func TestParams_Validate(t *testing.T) { + p := DefaultParams() + assert.Check(t, p.ClaimingFrequency > 0) + assert.Check(t, p.RebalancingFrequency > 0) +} diff --git a/x/metoken/price.go b/x/metoken/price.go new file mode 100644 index 0000000000..953cf20f10 --- /dev/null +++ b/x/metoken/price.go @@ -0,0 +1,103 @@ +package metoken + +import ( + "fmt" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + "github.com/umee-network/umee/v5/util/coin" +) + +// IndexPrices holds meToken and all the underlying assets Price. +type IndexPrices struct { + prices map[string]Price +} + +// Price contains usd Price from x/oracle and Exponent from x/leverage +type Price struct { + Price sdk.Dec + Exponent uint32 +} + +// NewIndexPrices creates an instance of IndexPrices. +func NewIndexPrices() IndexPrices { + return IndexPrices{prices: make(map[string]Price)} +} + +// Price returns a Price given a specific denom. +func (ip IndexPrices) Price(denom string) (Price, error) { + price, found := ip.prices[denom] + if !found || !price.Price.IsPositive() { + return Price{}, sdkerrors.ErrNotFound.Wrapf("price not found for denom %s", denom) + } + + return price, nil +} + +// SetPrice to the IndexPrices. +func (ip IndexPrices) SetPrice(denom string, price sdk.Dec, exponent uint32) { + ip.prices[denom] = Price{ + Price: price, + Exponent: exponent, + } +} + +// SwapRate converts one asset in the index to another applying exchange_rate and normalizing the exponent. +func (ip IndexPrices) SwapRate(from sdk.Coin, to string) (sdkmath.Int, error) { + exchangeRate, err := ip.rate(from.Denom, to) + if err != nil { + return sdkmath.Int{}, err + } + + exponentFactor, err := ip.ExponentFactor(from.Denom, to) + if err != nil { + return sdkmath.Int{}, err + } + + return exchangeRate.MulInt(from.Amount).Mul(exponentFactor).TruncateInt(), nil +} + +// rate calculates the exchange rate based on IndexPrices. +func (ip IndexPrices) rate(from, to string) (sdk.Dec, error) { + fromPrice, err := ip.Price(from) + if err != nil { + return sdk.Dec{}, err + } + + toPrice, err := ip.Price(to) + if err != nil { + return sdk.Dec{}, err + } + + return fromPrice.Price.Quo(toPrice.Price), nil +} + +// ExponentFactor calculates the multiplayer to be used to multiply from denom to get same decimals as to denom. +// If there is no such difference the result will be 1. +func (ip IndexPrices) ExponentFactor(from, to string) (sdk.Dec, error) { + fromPrice, err := ip.Price(from) + if err != nil { + return sdk.Dec{}, err + } + + toPrice, err := ip.Price(to) + if err != nil { + return sdk.Dec{}, err + } + + return ExponentFactor(fromPrice.Exponent, toPrice.Exponent) +} + +// ExponentFactor calculates the factor to multiply by which the assets with different exponents. +// If there is no such difference the result will be 1. +func ExponentFactor(initialExponent, resultExponent uint32) (sdk.Dec, error) { + exponentDiff := int(resultExponent) - int(initialExponent) + multiplier, ok := coin.Exponents[exponentDiff] + if !ok { + return sdk.Dec{}, fmt.Errorf("multiplier not found for exponentDiff %d", exponentDiff) + } + + return multiplier, nil +} diff --git a/x/metoken/query.pb.go b/x/metoken/query.pb.go new file mode 100644 index 0000000000..301c36cdcf --- /dev/null +++ b/x/metoken/query.pb.go @@ -0,0 +1,2136 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: umee/metoken/v1/query.proto + +package metoken + +import ( + context "context" + fmt "fmt" + types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/gogo/protobuf/gogoproto" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// QueryParams defines the request structure for the Params gRPC service +// handler. +type QueryParams struct { +} + +func (m *QueryParams) Reset() { *m = QueryParams{} } +func (m *QueryParams) String() string { return proto.CompactTextString(m) } +func (*QueryParams) ProtoMessage() {} +func (*QueryParams) Descriptor() ([]byte, []int) { + return fileDescriptor_2f141a376167f31d, []int{0} +} +func (m *QueryParams) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryParams) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryParams.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 *QueryParams) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParams.Merge(m, src) +} +func (m *QueryParams) XXX_Size() int { + return m.Size() +} +func (m *QueryParams) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParams.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryParams proto.InternalMessageInfo + +// QueryParamsResponse defines the response structure for the Params gRPC +// service handler. +type QueryParamsResponse struct { + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` +} + +func (m *QueryParamsResponse) Reset() { *m = QueryParamsResponse{} } +func (m *QueryParamsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryParamsResponse) ProtoMessage() {} +func (*QueryParamsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_2f141a376167f31d, []int{1} +} +func (m *QueryParamsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryParamsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryParamsResponse.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 *QueryParamsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParamsResponse.Merge(m, src) +} +func (m *QueryParamsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryParamsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParamsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryParamsResponse proto.InternalMessageInfo + +// QueryIndexes defines the request structure for the Indexes gRPC service handler. +// metoken_denom param is optional, if it is not informed the query will return all the Indexes. +type QueryIndexes struct { + MetokenDenom string `protobuf:"bytes,1,opt,name=metoken_denom,json=metokenDenom,proto3" json:"metoken_denom,omitempty"` +} + +func (m *QueryIndexes) Reset() { *m = QueryIndexes{} } +func (m *QueryIndexes) String() string { return proto.CompactTextString(m) } +func (*QueryIndexes) ProtoMessage() {} +func (*QueryIndexes) Descriptor() ([]byte, []int) { + return fileDescriptor_2f141a376167f31d, []int{2} +} +func (m *QueryIndexes) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryIndexes) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryIndexes.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 *QueryIndexes) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryIndexes.Merge(m, src) +} +func (m *QueryIndexes) XXX_Size() int { + return m.Size() +} +func (m *QueryIndexes) XXX_DiscardUnknown() { + xxx_messageInfo_QueryIndexes.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryIndexes proto.InternalMessageInfo + +// QueryIndexesResponse defines the response structure for the Indexes gRPC service handler. +type QueryIndexesResponse struct { + Registry []Index `protobuf:"bytes,1,rep,name=registry,proto3" json:"registry"` +} + +func (m *QueryIndexesResponse) Reset() { *m = QueryIndexesResponse{} } +func (m *QueryIndexesResponse) String() string { return proto.CompactTextString(m) } +func (*QueryIndexesResponse) ProtoMessage() {} +func (*QueryIndexesResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_2f141a376167f31d, []int{3} +} +func (m *QueryIndexesResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryIndexesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryIndexesResponse.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 *QueryIndexesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryIndexesResponse.Merge(m, src) +} +func (m *QueryIndexesResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryIndexesResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryIndexesResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryIndexesResponse proto.InternalMessageInfo + +// QuerySwapFee defines the request structure for the SwapFee gRPC service handler. +type QuerySwapFee struct { + Asset types.Coin `protobuf:"bytes,1,opt,name=asset,proto3" json:"asset"` + MetokenDenom string `protobuf:"bytes,2,opt,name=metoken_denom,json=metokenDenom,proto3" json:"metoken_denom,omitempty"` +} + +func (m *QuerySwapFee) Reset() { *m = QuerySwapFee{} } +func (m *QuerySwapFee) String() string { return proto.CompactTextString(m) } +func (*QuerySwapFee) ProtoMessage() {} +func (*QuerySwapFee) Descriptor() ([]byte, []int) { + return fileDescriptor_2f141a376167f31d, []int{4} +} +func (m *QuerySwapFee) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QuerySwapFee) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QuerySwapFee.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 *QuerySwapFee) XXX_Merge(src proto.Message) { + xxx_messageInfo_QuerySwapFee.Merge(m, src) +} +func (m *QuerySwapFee) XXX_Size() int { + return m.Size() +} +func (m *QuerySwapFee) XXX_DiscardUnknown() { + xxx_messageInfo_QuerySwapFee.DiscardUnknown(m) +} + +var xxx_messageInfo_QuerySwapFee proto.InternalMessageInfo + +// QuerySwapFeeResponse defines the response structure for the SwapFee gRPC service handler. +type QuerySwapFeeResponse struct { + Asset types.Coin `protobuf:"bytes,1,opt,name=asset,proto3" json:"asset"` +} + +func (m *QuerySwapFeeResponse) Reset() { *m = QuerySwapFeeResponse{} } +func (m *QuerySwapFeeResponse) String() string { return proto.CompactTextString(m) } +func (*QuerySwapFeeResponse) ProtoMessage() {} +func (*QuerySwapFeeResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_2f141a376167f31d, []int{5} +} +func (m *QuerySwapFeeResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QuerySwapFeeResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QuerySwapFeeResponse.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 *QuerySwapFeeResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QuerySwapFeeResponse.Merge(m, src) +} +func (m *QuerySwapFeeResponse) XXX_Size() int { + return m.Size() +} +func (m *QuerySwapFeeResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QuerySwapFeeResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QuerySwapFeeResponse proto.InternalMessageInfo + +// QueryRedeemFee defines the request structure for the RedeemFee gRPC service handler. +type QueryRedeemFee struct { + Metoken types.Coin `protobuf:"bytes,1,opt,name=metoken,proto3" json:"metoken"` + AssetDenom string `protobuf:"bytes,2,opt,name=asset_denom,json=assetDenom,proto3" json:"asset_denom,omitempty"` +} + +func (m *QueryRedeemFee) Reset() { *m = QueryRedeemFee{} } +func (m *QueryRedeemFee) String() string { return proto.CompactTextString(m) } +func (*QueryRedeemFee) ProtoMessage() {} +func (*QueryRedeemFee) Descriptor() ([]byte, []int) { + return fileDescriptor_2f141a376167f31d, []int{6} +} +func (m *QueryRedeemFee) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryRedeemFee) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryRedeemFee.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 *QueryRedeemFee) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryRedeemFee.Merge(m, src) +} +func (m *QueryRedeemFee) XXX_Size() int { + return m.Size() +} +func (m *QueryRedeemFee) XXX_DiscardUnknown() { + xxx_messageInfo_QueryRedeemFee.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryRedeemFee proto.InternalMessageInfo + +// QueryRedeemFeeResponse defines the response structure for the RedeemFee gRPC service handler. +type QueryRedeemFeeResponse struct { + Asset types.Coin `protobuf:"bytes,1,opt,name=asset,proto3" json:"asset"` +} + +func (m *QueryRedeemFeeResponse) Reset() { *m = QueryRedeemFeeResponse{} } +func (m *QueryRedeemFeeResponse) String() string { return proto.CompactTextString(m) } +func (*QueryRedeemFeeResponse) ProtoMessage() {} +func (*QueryRedeemFeeResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_2f141a376167f31d, []int{7} +} +func (m *QueryRedeemFeeResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryRedeemFeeResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryRedeemFeeResponse.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 *QueryRedeemFeeResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryRedeemFeeResponse.Merge(m, src) +} +func (m *QueryRedeemFeeResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryRedeemFeeResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryRedeemFeeResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryRedeemFeeResponse proto.InternalMessageInfo + +// QueryIndexBalances defines the request structure for the IndexBalances gRPC service handler. +// metoken_denom param is optional, if it is not informed the query will return all the Indexes. +type QueryIndexBalances struct { + MetokenDenom string `protobuf:"bytes,1,opt,name=metoken_denom,json=metokenDenom,proto3" json:"metoken_denom,omitempty"` +} + +func (m *QueryIndexBalances) Reset() { *m = QueryIndexBalances{} } +func (m *QueryIndexBalances) String() string { return proto.CompactTextString(m) } +func (*QueryIndexBalances) ProtoMessage() {} +func (*QueryIndexBalances) Descriptor() ([]byte, []int) { + return fileDescriptor_2f141a376167f31d, []int{8} +} +func (m *QueryIndexBalances) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryIndexBalances) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryIndexBalances.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 *QueryIndexBalances) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryIndexBalances.Merge(m, src) +} +func (m *QueryIndexBalances) XXX_Size() int { + return m.Size() +} +func (m *QueryIndexBalances) XXX_DiscardUnknown() { + xxx_messageInfo_QueryIndexBalances.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryIndexBalances proto.InternalMessageInfo + +// QueryIndexBalanceResponse defines the response structure for the IndexBalances gRPC service handler. +type QueryIndexBalancesResponse struct { + IndexBalances []IndexBalances `protobuf:"bytes,1,rep,name=index_balances,json=indexBalances,proto3" json:"index_balances"` +} + +func (m *QueryIndexBalancesResponse) Reset() { *m = QueryIndexBalancesResponse{} } +func (m *QueryIndexBalancesResponse) String() string { return proto.CompactTextString(m) } +func (*QueryIndexBalancesResponse) ProtoMessage() {} +func (*QueryIndexBalancesResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_2f141a376167f31d, []int{9} +} +func (m *QueryIndexBalancesResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryIndexBalancesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryIndexBalancesResponse.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 *QueryIndexBalancesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryIndexBalancesResponse.Merge(m, src) +} +func (m *QueryIndexBalancesResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryIndexBalancesResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryIndexBalancesResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryIndexBalancesResponse proto.InternalMessageInfo + +func init() { + proto.RegisterType((*QueryParams)(nil), "umeenetwork.umee.metoken.v1.QueryParams") + proto.RegisterType((*QueryParamsResponse)(nil), "umeenetwork.umee.metoken.v1.QueryParamsResponse") + proto.RegisterType((*QueryIndexes)(nil), "umeenetwork.umee.metoken.v1.QueryIndexes") + proto.RegisterType((*QueryIndexesResponse)(nil), "umeenetwork.umee.metoken.v1.QueryIndexesResponse") + proto.RegisterType((*QuerySwapFee)(nil), "umeenetwork.umee.metoken.v1.QuerySwapFee") + proto.RegisterType((*QuerySwapFeeResponse)(nil), "umeenetwork.umee.metoken.v1.QuerySwapFeeResponse") + proto.RegisterType((*QueryRedeemFee)(nil), "umeenetwork.umee.metoken.v1.QueryRedeemFee") + proto.RegisterType((*QueryRedeemFeeResponse)(nil), "umeenetwork.umee.metoken.v1.QueryRedeemFeeResponse") + proto.RegisterType((*QueryIndexBalances)(nil), "umeenetwork.umee.metoken.v1.QueryIndexBalances") + proto.RegisterType((*QueryIndexBalancesResponse)(nil), "umeenetwork.umee.metoken.v1.QueryIndexBalancesResponse") +} + +func init() { proto.RegisterFile("umee/metoken/v1/query.proto", fileDescriptor_2f141a376167f31d) } + +var fileDescriptor_2f141a376167f31d = []byte{ + // 637 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x95, 0x4f, 0x6f, 0xd3, 0x4c, + 0x10, 0xc6, 0xe3, 0xbe, 0x6f, 0x5b, 0xba, 0x69, 0x7a, 0x58, 0x2a, 0x68, 0x5d, 0xea, 0xb4, 0xce, + 0x81, 0x14, 0x84, 0x97, 0x24, 0xaa, 0x50, 0x8f, 0x84, 0x0a, 0xc4, 0x01, 0x01, 0xe1, 0x00, 0x42, + 0x48, 0xd1, 0x26, 0x19, 0x8c, 0x69, 0xbc, 0x6b, 0xbc, 0x4e, 0xd2, 0x5e, 0x91, 0x38, 0xc0, 0x09, + 0xc1, 0x37, 0xe0, 0xd3, 0xe4, 0x58, 0x89, 0x0b, 0x27, 0x04, 0x09, 0x1f, 0x04, 0x79, 0xbd, 0x76, + 0xf3, 0xa7, 0xa4, 0x2e, 0xdc, 0x9c, 0xd9, 0x79, 0x9e, 0xf9, 0xcd, 0xee, 0x8c, 0x82, 0x36, 0x3a, + 0x2e, 0x00, 0x71, 0x21, 0xe0, 0x07, 0xc0, 0x48, 0xb7, 0x44, 0xde, 0x74, 0xc0, 0x3f, 0xb2, 0x3c, + 0x9f, 0x07, 0x1c, 0xcb, 0x43, 0x06, 0x41, 0x8f, 0xfb, 0x07, 0x56, 0xf8, 0x6d, 0xa9, 0x44, 0xab, + 0x5b, 0xd2, 0xaf, 0xd8, 0x9c, 0xdb, 0x6d, 0x20, 0xd4, 0x73, 0x08, 0x65, 0x8c, 0x07, 0x34, 0x70, + 0x38, 0x13, 0x91, 0x54, 0x5f, 0xb5, 0xb9, 0xcd, 0xe5, 0x27, 0x09, 0xbf, 0x54, 0xd4, 0x68, 0x72, + 0xe1, 0x72, 0x41, 0x1a, 0x54, 0x00, 0xe9, 0x96, 0x1a, 0x10, 0xd0, 0x12, 0x69, 0x72, 0x87, 0xa9, + 0xf3, 0xcd, 0x49, 0x9a, 0xb8, 0xde, 0x1f, 0x8e, 0x6d, 0x60, 0x20, 0x1c, 0x55, 0xd3, 0xcc, 0xa1, + 0xec, 0xe3, 0x90, 0xfe, 0x11, 0xf5, 0xa9, 0x2b, 0xcc, 0x67, 0xe8, 0xe2, 0xc8, 0xcf, 0x1a, 0x08, + 0x8f, 0x33, 0x01, 0xf8, 0x36, 0x5a, 0xf0, 0x64, 0x64, 0x4d, 0xdb, 0xd2, 0x8a, 0xd9, 0x72, 0xc1, + 0x9a, 0xd1, 0xa5, 0x15, 0x89, 0xab, 0xff, 0xf7, 0xbf, 0xe7, 0x33, 0x35, 0x25, 0x34, 0x2b, 0x68, + 0x59, 0x3a, 0xdf, 0x67, 0x2d, 0x38, 0x04, 0x81, 0x0b, 0x28, 0xa7, 0x24, 0xf5, 0x16, 0x30, 0xee, + 0x4a, 0xe7, 0xa5, 0xda, 0xb2, 0x0a, 0xee, 0x87, 0x31, 0xf3, 0x05, 0x5a, 0x1d, 0x15, 0x25, 0x3c, + 0xfb, 0xe8, 0x82, 0x0f, 0xb6, 0x23, 0x02, 0xff, 0x68, 0x4d, 0xdb, 0xfa, 0xaf, 0x98, 0x2d, 0x9b, + 0x33, 0x89, 0xa4, 0x5e, 0x01, 0x25, 0x4a, 0xf3, 0xb5, 0x42, 0x7a, 0xd2, 0xa3, 0xde, 0x5d, 0x00, + 0xbc, 0x8b, 0xe6, 0xa9, 0x10, 0x10, 0xa8, 0x26, 0xd7, 0xad, 0xe8, 0xe6, 0xad, 0xf0, 0xe6, 0x2d, + 0x75, 0xf3, 0xd6, 0x1d, 0xee, 0x30, 0xe5, 0x14, 0x65, 0x4f, 0x77, 0x32, 0x77, 0x4a, 0x27, 0x0f, + 0x54, 0x27, 0xaa, 0x56, 0xd2, 0xc9, 0xdf, 0xd5, 0x34, 0xdb, 0x68, 0x45, 0xda, 0xd5, 0xa0, 0x05, + 0xe0, 0x86, 0xf0, 0x7b, 0x68, 0x51, 0x15, 0x4c, 0x6b, 0x15, 0xe7, 0xe3, 0x3c, 0xca, 0x4a, 0xd7, + 0x31, 0x7c, 0x24, 0x43, 0x11, 0xfc, 0x43, 0x74, 0x69, 0xbc, 0xda, 0xbf, 0xe2, 0xef, 0x21, 0x7c, + 0xf2, 0xae, 0x55, 0xda, 0xa6, 0xac, 0x99, 0x76, 0x24, 0x3a, 0x48, 0x9f, 0x96, 0x26, 0x3c, 0x4f, + 0xd1, 0x8a, 0x13, 0x1e, 0xd4, 0x1b, 0xea, 0x44, 0x8d, 0xc7, 0xb5, 0x14, 0xe3, 0xa1, 0x14, 0x8a, + 0x34, 0xe7, 0x8c, 0x06, 0xcb, 0x83, 0x79, 0x34, 0x2f, 0xeb, 0xe2, 0x77, 0x1a, 0x5a, 0x88, 0x26, + 0x1c, 0x17, 0x67, 0xba, 0x8e, 0x2c, 0x92, 0x7e, 0x33, 0x6d, 0x66, 0xdc, 0x89, 0x99, 0x7f, 0xfb, + 0xf5, 0xd7, 0xe7, 0xb9, 0x75, 0x7c, 0x99, 0x4c, 0x2e, 0x70, 0xb4, 0x50, 0xf8, 0xbd, 0x86, 0x16, + 0xe3, 0x65, 0xda, 0x39, 0xdb, 0x5e, 0xa5, 0xea, 0xa5, 0xd4, 0xa9, 0x09, 0xca, 0x96, 0x44, 0xd1, + 0xf1, 0xda, 0x14, 0x8a, 0xa3, 0xea, 0x7f, 0xd0, 0xd0, 0x62, 0xbc, 0x45, 0x29, 0x58, 0x54, 0x6a, + 0x1a, 0x96, 0x89, 0x7d, 0x31, 0xb7, 0x25, 0xcb, 0x06, 0x5e, 0x9f, 0x62, 0x11, 0x3d, 0xea, 0xd5, + 0x5f, 0x02, 0xe0, 0x4f, 0x1a, 0x5a, 0x3a, 0xd9, 0x8b, 0xeb, 0x67, 0xd7, 0x48, 0x92, 0xf5, 0xca, + 0x39, 0x92, 0x13, 0xa4, 0x82, 0x44, 0xda, 0xc4, 0x1b, 0x53, 0x48, 0xbe, 0xcc, 0x95, 0x50, 0x5f, + 0x34, 0x94, 0x1b, 0x9f, 0x76, 0x92, 0xf2, 0x21, 0x62, 0x81, 0x7e, 0xeb, 0x9c, 0x82, 0x04, 0xf0, + 0xaa, 0x04, 0xdc, 0xc6, 0xf9, 0xd3, 0xdf, 0x2f, 0xd9, 0x95, 0xea, 0xbd, 0xfe, 0x4f, 0x23, 0xd3, + 0x1f, 0x18, 0xda, 0xf1, 0xc0, 0xd0, 0x7e, 0x0c, 0x0c, 0xed, 0xe3, 0xd0, 0xc8, 0x1c, 0x0f, 0x8d, + 0xcc, 0xb7, 0xa1, 0x91, 0x79, 0xbe, 0x63, 0x3b, 0xc1, 0xab, 0x4e, 0xc3, 0x6a, 0x72, 0x57, 0x1a, + 0xdd, 0x50, 0x28, 0x91, 0x6b, 0x77, 0x97, 0x1c, 0xc6, 0xd6, 0x8d, 0x05, 0xf9, 0xe7, 0x52, 0xf9, + 0x1d, 0x00, 0x00, 0xff, 0xff, 0x88, 0xf6, 0x89, 0xd7, 0x2a, 0x07, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// QueryClient is the client API for Query service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type QueryClient interface { + // Params queries the parameters of the x/metoken module. + Params(ctx context.Context, in *QueryParams, opts ...grpc.CallOption) (*QueryParamsResponse, error) + // Indexes queries for a specific or all the registered indexes. + Indexes(ctx context.Context, in *QueryIndexes, opts ...grpc.CallOption) (*QueryIndexesResponse, error) + // SwapFee computes fee that would be applied when executing MsgSwap. + SwapFee(ctx context.Context, in *QuerySwapFee, opts ...grpc.CallOption) (*QuerySwapFeeResponse, error) + // RedeemFee computes a fee that would be applied when executing MsgRedeem. + RedeemFee(ctx context.Context, in *QueryRedeemFee, opts ...grpc.CallOption) (*QueryRedeemFeeResponse, error) + // IndexBalances queries for Index's balances of a specific or all the registered indexes. + IndexBalances(ctx context.Context, in *QueryIndexBalances, opts ...grpc.CallOption) (*QueryIndexBalancesResponse, error) +} + +type queryClient struct { + cc grpc1.ClientConn +} + +func NewQueryClient(cc grpc1.ClientConn) QueryClient { + return &queryClient{cc} +} + +func (c *queryClient) Params(ctx context.Context, in *QueryParams, opts ...grpc.CallOption) (*QueryParamsResponse, error) { + out := new(QueryParamsResponse) + err := c.cc.Invoke(ctx, "/umeenetwork.umee.metoken.v1.Query/Params", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) Indexes(ctx context.Context, in *QueryIndexes, opts ...grpc.CallOption) (*QueryIndexesResponse, error) { + out := new(QueryIndexesResponse) + err := c.cc.Invoke(ctx, "/umeenetwork.umee.metoken.v1.Query/Indexes", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) SwapFee(ctx context.Context, in *QuerySwapFee, opts ...grpc.CallOption) (*QuerySwapFeeResponse, error) { + out := new(QuerySwapFeeResponse) + err := c.cc.Invoke(ctx, "/umeenetwork.umee.metoken.v1.Query/SwapFee", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) RedeemFee(ctx context.Context, in *QueryRedeemFee, opts ...grpc.CallOption) (*QueryRedeemFeeResponse, error) { + out := new(QueryRedeemFeeResponse) + err := c.cc.Invoke(ctx, "/umeenetwork.umee.metoken.v1.Query/RedeemFee", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) IndexBalances(ctx context.Context, in *QueryIndexBalances, opts ...grpc.CallOption) (*QueryIndexBalancesResponse, error) { + out := new(QueryIndexBalancesResponse) + err := c.cc.Invoke(ctx, "/umeenetwork.umee.metoken.v1.Query/IndexBalances", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QueryServer is the server API for Query service. +type QueryServer interface { + // Params queries the parameters of the x/metoken module. + Params(context.Context, *QueryParams) (*QueryParamsResponse, error) + // Indexes queries for a specific or all the registered indexes. + Indexes(context.Context, *QueryIndexes) (*QueryIndexesResponse, error) + // SwapFee computes fee that would be applied when executing MsgSwap. + SwapFee(context.Context, *QuerySwapFee) (*QuerySwapFeeResponse, error) + // RedeemFee computes a fee that would be applied when executing MsgRedeem. + RedeemFee(context.Context, *QueryRedeemFee) (*QueryRedeemFeeResponse, error) + // IndexBalances queries for Index's balances of a specific or all the registered indexes. + IndexBalances(context.Context, *QueryIndexBalances) (*QueryIndexBalancesResponse, error) +} + +// UnimplementedQueryServer can be embedded to have forward compatible implementations. +type UnimplementedQueryServer struct { +} + +func (*UnimplementedQueryServer) Params(ctx context.Context, req *QueryParams) (*QueryParamsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Params not implemented") +} +func (*UnimplementedQueryServer) Indexes(ctx context.Context, req *QueryIndexes) (*QueryIndexesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Indexes not implemented") +} +func (*UnimplementedQueryServer) SwapFee(ctx context.Context, req *QuerySwapFee) (*QuerySwapFeeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SwapFee not implemented") +} +func (*UnimplementedQueryServer) RedeemFee(ctx context.Context, req *QueryRedeemFee) (*QueryRedeemFeeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RedeemFee not implemented") +} +func (*UnimplementedQueryServer) IndexBalances(ctx context.Context, req *QueryIndexBalances) (*QueryIndexBalancesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method IndexBalances not implemented") +} + +func RegisterQueryServer(s grpc1.Server, srv QueryServer) { + s.RegisterService(&_Query_serviceDesc, srv) +} + +func _Query_Params_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryParams) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).Params(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/umeenetwork.umee.metoken.v1.Query/Params", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).Params(ctx, req.(*QueryParams)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_Indexes_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryIndexes) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).Indexes(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/umeenetwork.umee.metoken.v1.Query/Indexes", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).Indexes(ctx, req.(*QueryIndexes)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_SwapFee_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QuerySwapFee) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).SwapFee(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/umeenetwork.umee.metoken.v1.Query/SwapFee", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).SwapFee(ctx, req.(*QuerySwapFee)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_RedeemFee_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryRedeemFee) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).RedeemFee(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/umeenetwork.umee.metoken.v1.Query/RedeemFee", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).RedeemFee(ctx, req.(*QueryRedeemFee)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_IndexBalances_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryIndexBalances) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).IndexBalances(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/umeenetwork.umee.metoken.v1.Query/IndexBalances", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).IndexBalances(ctx, req.(*QueryIndexBalances)) + } + return interceptor(ctx, in, info, handler) +} + +var _Query_serviceDesc = grpc.ServiceDesc{ + ServiceName: "umeenetwork.umee.metoken.v1.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Params", + Handler: _Query_Params_Handler, + }, + { + MethodName: "Indexes", + Handler: _Query_Indexes_Handler, + }, + { + MethodName: "SwapFee", + Handler: _Query_SwapFee_Handler, + }, + { + MethodName: "RedeemFee", + Handler: _Query_RedeemFee_Handler, + }, + { + MethodName: "IndexBalances", + Handler: _Query_IndexBalances_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "umee/metoken/v1/query.proto", +} + +func (m *QueryParams) 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 *QueryParams) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryParamsResponse) 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 *QueryParamsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *QueryIndexes) 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 *QueryIndexes) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryIndexes) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.MetokenDenom) > 0 { + i -= len(m.MetokenDenom) + copy(dAtA[i:], m.MetokenDenom) + i = encodeVarintQuery(dAtA, i, uint64(len(m.MetokenDenom))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryIndexesResponse) 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 *QueryIndexesResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryIndexesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Registry) > 0 { + for iNdEx := len(m.Registry) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Registry[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QuerySwapFee) 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 *QuerySwapFee) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QuerySwapFee) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.MetokenDenom) > 0 { + i -= len(m.MetokenDenom) + copy(dAtA[i:], m.MetokenDenom) + i = encodeVarintQuery(dAtA, i, uint64(len(m.MetokenDenom))) + i-- + dAtA[i] = 0x12 + } + { + size, err := m.Asset.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *QuerySwapFeeResponse) 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 *QuerySwapFeeResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QuerySwapFeeResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Asset.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *QueryRedeemFee) 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 *QueryRedeemFee) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryRedeemFee) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.AssetDenom) > 0 { + i -= len(m.AssetDenom) + copy(dAtA[i:], m.AssetDenom) + i = encodeVarintQuery(dAtA, i, uint64(len(m.AssetDenom))) + i-- + dAtA[i] = 0x12 + } + { + size, err := m.Metoken.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *QueryRedeemFeeResponse) 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 *QueryRedeemFeeResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryRedeemFeeResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Asset.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *QueryIndexBalances) 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 *QueryIndexBalances) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryIndexBalances) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.MetokenDenom) > 0 { + i -= len(m.MetokenDenom) + copy(dAtA[i:], m.MetokenDenom) + i = encodeVarintQuery(dAtA, i, uint64(len(m.MetokenDenom))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryIndexBalancesResponse) 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 *QueryIndexBalancesResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryIndexBalancesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.IndexBalances) > 0 { + for iNdEx := len(m.IndexBalances) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.IndexBalances[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { + offset -= sovQuery(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *QueryParams) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryParamsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *QueryIndexes) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.MetokenDenom) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryIndexesResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Registry) > 0 { + for _, e := range m.Registry { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func (m *QuerySwapFee) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Asset.Size() + n += 1 + l + sovQuery(uint64(l)) + l = len(m.MetokenDenom) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QuerySwapFeeResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Asset.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *QueryRedeemFee) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Metoken.Size() + n += 1 + l + sovQuery(uint64(l)) + l = len(m.AssetDenom) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryRedeemFeeResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Asset.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *QueryIndexBalances) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.MetokenDenom) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryIndexBalancesResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.IndexBalances) > 0 { + for _, e := range m.IndexBalances { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func sovQuery(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozQuery(x uint64) (n int) { + return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *QueryParams) 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 ErrIntOverflowQuery + } + 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: QueryParams: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryParams: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryParamsResponse) 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 ErrIntOverflowQuery + } + 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: QueryParamsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryParamsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryIndexes) 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 ErrIntOverflowQuery + } + 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: QueryIndexes: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryIndexes: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MetokenDenom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.MetokenDenom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryIndexesResponse) 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 ErrIntOverflowQuery + } + 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: QueryIndexesResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryIndexesResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Registry", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Registry = append(m.Registry, Index{}) + if err := m.Registry[len(m.Registry)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QuerySwapFee) 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 ErrIntOverflowQuery + } + 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: QuerySwapFee: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QuerySwapFee: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Asset", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Asset.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MetokenDenom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.MetokenDenom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QuerySwapFeeResponse) 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 ErrIntOverflowQuery + } + 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: QuerySwapFeeResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QuerySwapFeeResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Asset", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Asset.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryRedeemFee) 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 ErrIntOverflowQuery + } + 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: QueryRedeemFee: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryRedeemFee: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Metoken", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Metoken.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AssetDenom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AssetDenom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryRedeemFeeResponse) 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 ErrIntOverflowQuery + } + 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: QueryRedeemFeeResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryRedeemFeeResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Asset", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Asset.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryIndexBalances) 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 ErrIntOverflowQuery + } + 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: QueryIndexBalances: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryIndexBalances: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MetokenDenom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.MetokenDenom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryIndexBalancesResponse) 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 ErrIntOverflowQuery + } + 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: QueryIndexBalancesResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryIndexBalancesResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field IndexBalances", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.IndexBalances = append(m.IndexBalances, IndexBalances{}) + if err := m.IndexBalances[len(m.IndexBalances)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipQuery(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthQuery + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupQuery + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthQuery + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthQuery = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowQuery = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupQuery = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/metoken/query.pb.gw.go b/x/metoken/query.pb.gw.go new file mode 100644 index 0000000000..e81f2ded45 --- /dev/null +++ b/x/metoken/query.pb.gw.go @@ -0,0 +1,485 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: umee/metoken/v1/query.proto + +/* +Package metoken is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package metoken + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage +var _ = metadata.Join + +func request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryParams + var metadata runtime.ServerMetadata + + msg, err := client.Params(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryParams + var metadata runtime.ServerMetadata + + msg, err := server.Params(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_Indexes_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_Indexes_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryIndexes + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_Indexes_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.Indexes(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_Indexes_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryIndexes + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_Indexes_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.Indexes(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_SwapFee_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_SwapFee_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QuerySwapFee + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_SwapFee_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.SwapFee(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_SwapFee_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QuerySwapFee + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_SwapFee_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.SwapFee(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_RedeemFee_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_RedeemFee_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryRedeemFee + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_RedeemFee_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.RedeemFee(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_RedeemFee_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryRedeemFee + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_RedeemFee_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.RedeemFee(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_IndexBalances_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_IndexBalances_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryIndexBalances + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_IndexBalances_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.IndexBalances(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_IndexBalances_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryIndexBalances + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_IndexBalances_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.IndexBalances(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterQueryHandlerServer registers the http handlers for service Query to "mux". +// UnaryRPC :call QueryServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. +func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { + + mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_Params_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_Indexes_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_Indexes_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Indexes_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_SwapFee_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_SwapFee_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_SwapFee_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_RedeemFee_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_RedeemFee_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_RedeemFee_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_IndexBalances_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_IndexBalances_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_IndexBalances_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterQueryHandlerFromEndpoint is same as RegisterQueryHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterQueryHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterQueryHandler(ctx, mux, conn) +} + +// RegisterQueryHandler registers the http handlers for service Query to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterQueryHandlerClient(ctx, mux, NewQueryClient(conn)) +} + +// RegisterQueryHandlerClient registers the http handlers for service Query +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "QueryClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "QueryClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "QueryClient" to call the correct interceptors. +func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error { + + mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_Params_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_Indexes_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_Indexes_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Indexes_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_SwapFee_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_SwapFee_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_SwapFee_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_RedeemFee_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_RedeemFee_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_RedeemFee_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_IndexBalances_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_IndexBalances_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_IndexBalances_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"umee", "metoken", "v1", "params"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_Indexes_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"umee", "metoken", "v1", "indexes"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_SwapFee_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"umee", "metoken", "v1", "swap_fee"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_RedeemFee_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"umee", "metoken", "v1", "redeem_fee"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_IndexBalances_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"umee", "metoken", "v1", "index_balances"}, "", runtime.AssumeColonVerbOpt(false))) +) + +var ( + forward_Query_Params_0 = runtime.ForwardResponseMessage + + forward_Query_Indexes_0 = runtime.ForwardResponseMessage + + forward_Query_SwapFee_0 = runtime.ForwardResponseMessage + + forward_Query_RedeemFee_0 = runtime.ForwardResponseMessage + + forward_Query_IndexBalances_0 = runtime.ForwardResponseMessage +) diff --git a/x/metoken/tx.pb.go b/x/metoken/tx.pb.go new file mode 100644 index 0000000000..350b868134 --- /dev/null +++ b/x/metoken/tx.pb.go @@ -0,0 +1,2115 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: umee/metoken/v1/tx.proto + +package metoken + +import ( + context "context" + fmt "fmt" + _ "github.com/cosmos/cosmos-proto" + types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/cosmos-sdk/types/msgservice" + _ "github.com/gogo/protobuf/gogoproto" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// MsgSwap represents a user's request to swap assets for Index's meToken. +type MsgSwap struct { + // User is the account address swapping assets and the signer of the message. + User string `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` + Asset types.Coin `protobuf:"bytes,2,opt,name=asset,proto3" json:"asset"` + MetokenDenom string `protobuf:"bytes,3,opt,name=metoken_denom,json=metokenDenom,proto3" json:"metoken_denom,omitempty"` +} + +func (m *MsgSwap) Reset() { *m = MsgSwap{} } +func (m *MsgSwap) String() string { return proto.CompactTextString(m) } +func (*MsgSwap) ProtoMessage() {} +func (*MsgSwap) Descriptor() ([]byte, []int) { + return fileDescriptor_4fa56b8f5850b02d, []int{0} +} +func (m *MsgSwap) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSwap) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSwap.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 *MsgSwap) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSwap.Merge(m, src) +} +func (m *MsgSwap) XXX_Size() int { + return m.Size() +} +func (m *MsgSwap) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSwap.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSwap proto.InternalMessageInfo + +// MsgSwapResponse defines the Msg/Swap response type. +type MsgSwapResponse struct { + // Fee is the amount of accepted asset charged to the user as the fee for the transaction. + Fee types.Coin `protobuf:"bytes,1,opt,name=fee,proto3" json:"fee"` + // Returned is the amount of Index's meToken minted and returned to the user. + Returned types.Coin `protobuf:"bytes,2,opt,name=returned,proto3" json:"returned"` +} + +func (m *MsgSwapResponse) Reset() { *m = MsgSwapResponse{} } +func (m *MsgSwapResponse) String() string { return proto.CompactTextString(m) } +func (*MsgSwapResponse) ProtoMessage() {} +func (*MsgSwapResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_4fa56b8f5850b02d, []int{1} +} +func (m *MsgSwapResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSwapResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSwapResponse.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 *MsgSwapResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSwapResponse.Merge(m, src) +} +func (m *MsgSwapResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgSwapResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSwapResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSwapResponse proto.InternalMessageInfo + +// MsgRedeem represents a user's request to redeem Index's meTokens for one of the accepted assets. +type MsgRedeem struct { + // User is the account address redeeming assets and the signer of the message. + User string `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` + Metoken types.Coin `protobuf:"bytes,2,opt,name=metoken,proto3" json:"metoken"` + AssetDenom string `protobuf:"bytes,3,opt,name=asset_denom,json=assetDenom,proto3" json:"asset_denom,omitempty"` +} + +func (m *MsgRedeem) Reset() { *m = MsgRedeem{} } +func (m *MsgRedeem) String() string { return proto.CompactTextString(m) } +func (*MsgRedeem) ProtoMessage() {} +func (*MsgRedeem) Descriptor() ([]byte, []int) { + return fileDescriptor_4fa56b8f5850b02d, []int{2} +} +func (m *MsgRedeem) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgRedeem) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgRedeem.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 *MsgRedeem) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRedeem.Merge(m, src) +} +func (m *MsgRedeem) XXX_Size() int { + return m.Size() +} +func (m *MsgRedeem) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRedeem.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgRedeem proto.InternalMessageInfo + +// MsgRedeemResponse defines the Msg/Redeem response type. +type MsgRedeemResponse struct { + // Returned is the amount of accepted asset returned to the user. + Returned types.Coin `protobuf:"bytes,1,opt,name=returned,proto3" json:"returned"` + // Fee is the amount of accepted asset charged to the user as the fee for the transaction. + Fee types.Coin `protobuf:"bytes,2,opt,name=fee,proto3" json:"fee"` +} + +func (m *MsgRedeemResponse) Reset() { *m = MsgRedeemResponse{} } +func (m *MsgRedeemResponse) String() string { return proto.CompactTextString(m) } +func (*MsgRedeemResponse) ProtoMessage() {} +func (*MsgRedeemResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_4fa56b8f5850b02d, []int{3} +} +func (m *MsgRedeemResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgRedeemResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgRedeemResponse.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 *MsgRedeemResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRedeemResponse.Merge(m, src) +} +func (m *MsgRedeemResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgRedeemResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRedeemResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgRedeemResponse proto.InternalMessageInfo + +// MsgGovSetParams defines the Msg/GovSetParams request type. +type MsgGovSetParams struct { + // authority must be the address of the governance account. + Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` + Params Params `protobuf:"bytes,2,opt,name=params,proto3" json:"params"` +} + +func (m *MsgGovSetParams) Reset() { *m = MsgGovSetParams{} } +func (m *MsgGovSetParams) String() string { return proto.CompactTextString(m) } +func (*MsgGovSetParams) ProtoMessage() {} +func (*MsgGovSetParams) Descriptor() ([]byte, []int) { + return fileDescriptor_4fa56b8f5850b02d, []int{4} +} +func (m *MsgGovSetParams) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgGovSetParams) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgGovSetParams.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 *MsgGovSetParams) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgGovSetParams.Merge(m, src) +} +func (m *MsgGovSetParams) XXX_Size() int { + return m.Size() +} +func (m *MsgGovSetParams) XXX_DiscardUnknown() { + xxx_messageInfo_MsgGovSetParams.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgGovSetParams proto.InternalMessageInfo + +// MsgGovSetParamsResponse defines the Msg/GovSetParams response type. +type MsgGovSetParamsResponse struct { +} + +func (m *MsgGovSetParamsResponse) Reset() { *m = MsgGovSetParamsResponse{} } +func (m *MsgGovSetParamsResponse) String() string { return proto.CompactTextString(m) } +func (*MsgGovSetParamsResponse) ProtoMessage() {} +func (*MsgGovSetParamsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_4fa56b8f5850b02d, []int{5} +} +func (m *MsgGovSetParamsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgGovSetParamsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgGovSetParamsResponse.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 *MsgGovSetParamsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgGovSetParamsResponse.Merge(m, src) +} +func (m *MsgGovSetParamsResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgGovSetParamsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgGovSetParamsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgGovSetParamsResponse proto.InternalMessageInfo + +// MsgGovUpdateRegistry defines the Msg/GovUpdateRegistry request type. +type MsgGovUpdateRegistry struct { + // authority is the address of the governance account. + Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` + // add_index defines new index settings. + AddIndex []Index `protobuf:"bytes,2,rep,name=add_index,json=addIndex,proto3" json:"add_index"` + // update_index defines the new settings for existing index. + UpdateIndex []Index `protobuf:"bytes,3,rep,name=update_index,json=updateIndex,proto3" json:"update_index"` +} + +func (m *MsgGovUpdateRegistry) Reset() { *m = MsgGovUpdateRegistry{} } +func (m *MsgGovUpdateRegistry) String() string { return proto.CompactTextString(m) } +func (*MsgGovUpdateRegistry) ProtoMessage() {} +func (*MsgGovUpdateRegistry) Descriptor() ([]byte, []int) { + return fileDescriptor_4fa56b8f5850b02d, []int{6} +} +func (m *MsgGovUpdateRegistry) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgGovUpdateRegistry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgGovUpdateRegistry.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 *MsgGovUpdateRegistry) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgGovUpdateRegistry.Merge(m, src) +} +func (m *MsgGovUpdateRegistry) XXX_Size() int { + return m.Size() +} +func (m *MsgGovUpdateRegistry) XXX_DiscardUnknown() { + xxx_messageInfo_MsgGovUpdateRegistry.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgGovUpdateRegistry proto.InternalMessageInfo + +// MsgGovUpdateRegistryResponse defines the Msg/GovUpdateRegistry response type. +type MsgGovUpdateRegistryResponse struct { +} + +func (m *MsgGovUpdateRegistryResponse) Reset() { *m = MsgGovUpdateRegistryResponse{} } +func (m *MsgGovUpdateRegistryResponse) String() string { return proto.CompactTextString(m) } +func (*MsgGovUpdateRegistryResponse) ProtoMessage() {} +func (*MsgGovUpdateRegistryResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_4fa56b8f5850b02d, []int{7} +} +func (m *MsgGovUpdateRegistryResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgGovUpdateRegistryResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgGovUpdateRegistryResponse.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 *MsgGovUpdateRegistryResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgGovUpdateRegistryResponse.Merge(m, src) +} +func (m *MsgGovUpdateRegistryResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgGovUpdateRegistryResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgGovUpdateRegistryResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgGovUpdateRegistryResponse proto.InternalMessageInfo + +func init() { + proto.RegisterType((*MsgSwap)(nil), "umeenetwork.umee.metoken.v1.MsgSwap") + proto.RegisterType((*MsgSwapResponse)(nil), "umeenetwork.umee.metoken.v1.MsgSwapResponse") + proto.RegisterType((*MsgRedeem)(nil), "umeenetwork.umee.metoken.v1.MsgRedeem") + proto.RegisterType((*MsgRedeemResponse)(nil), "umeenetwork.umee.metoken.v1.MsgRedeemResponse") + proto.RegisterType((*MsgGovSetParams)(nil), "umeenetwork.umee.metoken.v1.MsgGovSetParams") + proto.RegisterType((*MsgGovSetParamsResponse)(nil), "umeenetwork.umee.metoken.v1.MsgGovSetParamsResponse") + proto.RegisterType((*MsgGovUpdateRegistry)(nil), "umeenetwork.umee.metoken.v1.MsgGovUpdateRegistry") + proto.RegisterType((*MsgGovUpdateRegistryResponse)(nil), "umeenetwork.umee.metoken.v1.MsgGovUpdateRegistryResponse") +} + +func init() { proto.RegisterFile("umee/metoken/v1/tx.proto", fileDescriptor_4fa56b8f5850b02d) } + +var fileDescriptor_4fa56b8f5850b02d = []byte{ + // 635 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x54, 0x4d, 0x4f, 0xd4, 0x40, + 0x18, 0xde, 0x61, 0x11, 0xdc, 0x77, 0x31, 0x86, 0x09, 0x09, 0x4b, 0xd5, 0x42, 0x8a, 0x31, 0x68, + 0xa4, 0x4d, 0x51, 0x4c, 0xd0, 0x13, 0xa8, 0x21, 0xc6, 0x90, 0x98, 0x12, 0x2f, 0x5c, 0xb0, 0x4b, + 0x5f, 0x4b, 0x43, 0xda, 0xd9, 0x74, 0xa6, 0x0b, 0xc4, 0x13, 0xfa, 0x07, 0xfc, 0x09, 0xfc, 0x04, + 0x0f, 0xde, 0xfc, 0x03, 0x1c, 0x89, 0x27, 0x4f, 0x46, 0xe1, 0xa0, 0xbf, 0xc0, 0xb3, 0xe9, 0xcc, + 0xb4, 0x7c, 0x48, 0x96, 0xae, 0xb7, 0x99, 0x79, 0x9f, 0xf7, 0x79, 0x9e, 0xf7, 0xe9, 0x4c, 0xa1, + 0x95, 0xc5, 0x88, 0x4e, 0x8c, 0x82, 0x6d, 0x61, 0xe2, 0x74, 0x5d, 0x47, 0xec, 0xd8, 0x9d, 0x94, + 0x09, 0x46, 0x6f, 0xe4, 0x95, 0x04, 0xc5, 0x36, 0x4b, 0xb7, 0xec, 0x7c, 0x6d, 0x6b, 0x94, 0xdd, + 0x75, 0x0d, 0x73, 0x83, 0xf1, 0x98, 0x71, 0xa7, 0xed, 0x73, 0x74, 0xba, 0x6e, 0x1b, 0x85, 0xef, + 0x3a, 0x1b, 0x2c, 0x4a, 0x54, 0xb3, 0x31, 0xa1, 0xea, 0xeb, 0x72, 0xe7, 0xa8, 0x8d, 0x2e, 0x8d, + 0xeb, 0xd6, 0x98, 0x87, 0xb9, 0x5e, 0xcc, 0x43, 0x5d, 0x18, 0x0b, 0x59, 0xc8, 0x54, 0x43, 0xbe, + 0xd2, 0xa7, 0xb7, 0xce, 0x1b, 0x2c, 0x5c, 0xc8, 0xb2, 0xb5, 0x0b, 0xc3, 0x2b, 0x3c, 0x5c, 0xdd, + 0xf6, 0x3b, 0x94, 0xc2, 0x60, 0xc6, 0x31, 0x6d, 0x91, 0x29, 0x32, 0xd3, 0xf0, 0xe4, 0x9a, 0xce, + 0xc3, 0x15, 0x9f, 0x73, 0x14, 0xad, 0x81, 0x29, 0x32, 0xd3, 0x9c, 0x9b, 0xb0, 0xb5, 0x95, 0xdc, + 0xb7, 0xad, 0x7d, 0xdb, 0x4f, 0x59, 0x94, 0x2c, 0x0d, 0x1e, 0x7c, 0x9f, 0xac, 0x79, 0x0a, 0x4d, + 0xa7, 0xe1, 0x9a, 0x96, 0x59, 0x0f, 0x30, 0x61, 0x71, 0xab, 0x2e, 0x39, 0x47, 0xf4, 0xe1, 0xb3, + 0xfc, 0xcc, 0xda, 0x23, 0x70, 0x5d, 0x6b, 0x7b, 0xc8, 0x3b, 0x2c, 0xe1, 0x48, 0x5d, 0xa8, 0xbf, + 0x45, 0x94, 0x16, 0x2a, 0xa8, 0xe5, 0x58, 0xfa, 0x04, 0xae, 0xa6, 0x28, 0xb2, 0x34, 0xc1, 0xa0, + 0xaa, 0xcb, 0xb2, 0xc1, 0x7a, 0x07, 0x8d, 0x15, 0x1e, 0x7a, 0x18, 0x20, 0xc6, 0x17, 0x06, 0xb0, + 0x00, 0xc3, 0xda, 0x74, 0x55, 0xf2, 0x02, 0x4f, 0x27, 0xa1, 0x29, 0xd3, 0x38, 0x13, 0x01, 0xc8, + 0x23, 0x15, 0xc0, 0x07, 0x02, 0xa3, 0xa5, 0x7a, 0x19, 0xc1, 0xe9, 0x79, 0x48, 0x9f, 0xf3, 0x14, + 0xf9, 0x0d, 0x54, 0xcf, 0xcf, 0xda, 0x57, 0x9f, 0x61, 0x99, 0x75, 0x57, 0x51, 0xbc, 0xf2, 0x53, + 0x3f, 0xe6, 0xf4, 0x11, 0x34, 0xfc, 0x4c, 0x6c, 0xb2, 0x34, 0x12, 0xbb, 0x2a, 0x8e, 0xa5, 0xd6, + 0xd7, 0xcf, 0xb3, 0x63, 0x9a, 0x6f, 0x31, 0x08, 0x52, 0xe4, 0x7c, 0x55, 0xa4, 0x51, 0x12, 0x7a, + 0x27, 0x50, 0xba, 0x08, 0x43, 0x1d, 0xc9, 0xa0, 0x1d, 0x4c, 0xdb, 0x3d, 0x1e, 0x81, 0xad, 0xc4, + 0xb4, 0x17, 0xdd, 0xf8, 0x98, 0xfe, 0xde, 0x9f, 0x24, 0xef, 0x7f, 0x7d, 0xba, 0x77, 0x42, 0x6b, + 0x4d, 0xc0, 0xf8, 0x39, 0x87, 0x45, 0x5a, 0xd6, 0x1f, 0x02, 0x63, 0xaa, 0xf6, 0xba, 0x13, 0xf8, + 0x02, 0x3d, 0x0c, 0x23, 0x2e, 0xd2, 0xdd, 0xff, 0x1e, 0xe1, 0x39, 0x34, 0xfc, 0x20, 0x58, 0x8f, + 0x92, 0x00, 0x77, 0x5a, 0x03, 0x53, 0xf5, 0x99, 0xe6, 0x9c, 0xd5, 0x73, 0x8a, 0x17, 0x39, 0xb2, + 0xf8, 0x10, 0x7e, 0x10, 0xc8, 0x3d, 0x7d, 0x09, 0x23, 0x99, 0x34, 0xa4, 0x99, 0xea, 0x7d, 0x32, + 0x35, 0x55, 0xb7, 0x3c, 0xba, 0x30, 0x13, 0x13, 0x6e, 0x5e, 0x34, 0x77, 0x11, 0xcc, 0xdc, 0x97, + 0x3a, 0xd4, 0x57, 0x78, 0x48, 0xd7, 0x60, 0x50, 0xbe, 0xee, 0xdb, 0x3d, 0xa5, 0xf5, 0x3b, 0x34, + 0xee, 0x57, 0x41, 0x95, 0x57, 0xf5, 0x0d, 0x0c, 0xe9, 0xa7, 0x73, 0xe7, 0xb2, 0x3e, 0x85, 0x33, + 0xec, 0x6a, 0xb8, 0x52, 0x21, 0x85, 0x91, 0x33, 0x17, 0xf3, 0x52, 0x7f, 0xa7, 0xd1, 0xc6, 0xc3, + 0x7e, 0xd0, 0xa5, 0xe6, 0x1e, 0x81, 0xd1, 0x7f, 0xef, 0x93, 0x5b, 0x81, 0xeb, 0x6c, 0x8b, 0xb1, + 0xd0, 0x77, 0x4b, 0xe1, 0x61, 0x69, 0xf9, 0xe0, 0xa7, 0x59, 0x3b, 0x38, 0x32, 0xc9, 0xe1, 0x91, + 0x49, 0x7e, 0x1c, 0x99, 0xe4, 0xe3, 0xb1, 0x59, 0x3b, 0x3c, 0x36, 0x6b, 0xdf, 0x8e, 0xcd, 0xda, + 0xda, 0xdd, 0x30, 0x12, 0x9b, 0x59, 0xdb, 0xde, 0x60, 0xb1, 0x93, 0xd3, 0xce, 0x6a, 0x0d, 0xb9, + 0x71, 0xba, 0xf3, 0xce, 0x4e, 0xf1, 0x97, 0x6f, 0x0f, 0xc9, 0xdf, 0xfc, 0x83, 0xbf, 0x01, 0x00, + 0x00, 0xff, 0xff, 0x24, 0x21, 0x3e, 0xb5, 0xa8, 0x06, 0x00, 0x00, +} + +func (this *MsgGovSetParams) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*MsgGovSetParams) + if !ok { + that2, ok := that.(MsgGovSetParams) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Authority != that1.Authority { + return false + } + if !this.Params.Equal(&that1.Params) { + return false + } + return true +} +func (this *MsgGovUpdateRegistry) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*MsgGovUpdateRegistry) + if !ok { + that2, ok := that.(MsgGovUpdateRegistry) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Authority != that1.Authority { + return false + } + if len(this.AddIndex) != len(that1.AddIndex) { + return false + } + for i := range this.AddIndex { + if !this.AddIndex[i].Equal(&that1.AddIndex[i]) { + return false + } + } + if len(this.UpdateIndex) != len(that1.UpdateIndex) { + return false + } + for i := range this.UpdateIndex { + if !this.UpdateIndex[i].Equal(&that1.UpdateIndex[i]) { + return false + } + } + return true +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// MsgClient is the client API for Msg service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type MsgClient interface { + // Swap defines a method for swapping an accepted asset for Index's meToken. + Swap(ctx context.Context, in *MsgSwap, opts ...grpc.CallOption) (*MsgSwapResponse, error) + // Redeem defines a method for redeeming Index's meToken for an accepted asset. + Redeem(ctx context.Context, in *MsgRedeem, opts ...grpc.CallOption) (*MsgRedeemResponse, error) + // GovSetParams is used by governance proposals to update parameters. + GovSetParams(ctx context.Context, in *MsgGovSetParams, opts ...grpc.CallOption) (*MsgGovSetParamsResponse, error) + // GovUpdateRegistry adds new index to the index registry or + // updates existing index with new settings. + GovUpdateRegistry(ctx context.Context, in *MsgGovUpdateRegistry, opts ...grpc.CallOption) (*MsgGovUpdateRegistryResponse, error) +} + +type msgClient struct { + cc grpc1.ClientConn +} + +func NewMsgClient(cc grpc1.ClientConn) MsgClient { + return &msgClient{cc} +} + +func (c *msgClient) Swap(ctx context.Context, in *MsgSwap, opts ...grpc.CallOption) (*MsgSwapResponse, error) { + out := new(MsgSwapResponse) + err := c.cc.Invoke(ctx, "/umeenetwork.umee.metoken.v1.Msg/Swap", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) Redeem(ctx context.Context, in *MsgRedeem, opts ...grpc.CallOption) (*MsgRedeemResponse, error) { + out := new(MsgRedeemResponse) + err := c.cc.Invoke(ctx, "/umeenetwork.umee.metoken.v1.Msg/Redeem", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) GovSetParams(ctx context.Context, in *MsgGovSetParams, opts ...grpc.CallOption) (*MsgGovSetParamsResponse, error) { + out := new(MsgGovSetParamsResponse) + err := c.cc.Invoke(ctx, "/umeenetwork.umee.metoken.v1.Msg/GovSetParams", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) GovUpdateRegistry(ctx context.Context, in *MsgGovUpdateRegistry, opts ...grpc.CallOption) (*MsgGovUpdateRegistryResponse, error) { + out := new(MsgGovUpdateRegistryResponse) + err := c.cc.Invoke(ctx, "/umeenetwork.umee.metoken.v1.Msg/GovUpdateRegistry", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MsgServer is the server API for Msg service. +type MsgServer interface { + // Swap defines a method for swapping an accepted asset for Index's meToken. + Swap(context.Context, *MsgSwap) (*MsgSwapResponse, error) + // Redeem defines a method for redeeming Index's meToken for an accepted asset. + Redeem(context.Context, *MsgRedeem) (*MsgRedeemResponse, error) + // GovSetParams is used by governance proposals to update parameters. + GovSetParams(context.Context, *MsgGovSetParams) (*MsgGovSetParamsResponse, error) + // GovUpdateRegistry adds new index to the index registry or + // updates existing index with new settings. + GovUpdateRegistry(context.Context, *MsgGovUpdateRegistry) (*MsgGovUpdateRegistryResponse, error) +} + +// UnimplementedMsgServer can be embedded to have forward compatible implementations. +type UnimplementedMsgServer struct { +} + +func (*UnimplementedMsgServer) Swap(ctx context.Context, req *MsgSwap) (*MsgSwapResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Swap not implemented") +} +func (*UnimplementedMsgServer) Redeem(ctx context.Context, req *MsgRedeem) (*MsgRedeemResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Redeem not implemented") +} +func (*UnimplementedMsgServer) GovSetParams(ctx context.Context, req *MsgGovSetParams) (*MsgGovSetParamsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GovSetParams not implemented") +} +func (*UnimplementedMsgServer) GovUpdateRegistry(ctx context.Context, req *MsgGovUpdateRegistry) (*MsgGovUpdateRegistryResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GovUpdateRegistry not implemented") +} + +func RegisterMsgServer(s grpc1.Server, srv MsgServer) { + s.RegisterService(&_Msg_serviceDesc, srv) +} + +func _Msg_Swap_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgSwap) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).Swap(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/umeenetwork.umee.metoken.v1.Msg/Swap", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).Swap(ctx, req.(*MsgSwap)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_Redeem_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgRedeem) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).Redeem(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/umeenetwork.umee.metoken.v1.Msg/Redeem", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).Redeem(ctx, req.(*MsgRedeem)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_GovSetParams_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgGovSetParams) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).GovSetParams(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/umeenetwork.umee.metoken.v1.Msg/GovSetParams", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).GovSetParams(ctx, req.(*MsgGovSetParams)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_GovUpdateRegistry_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgGovUpdateRegistry) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).GovUpdateRegistry(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/umeenetwork.umee.metoken.v1.Msg/GovUpdateRegistry", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).GovUpdateRegistry(ctx, req.(*MsgGovUpdateRegistry)) + } + return interceptor(ctx, in, info, handler) +} + +var _Msg_serviceDesc = grpc.ServiceDesc{ + ServiceName: "umeenetwork.umee.metoken.v1.Msg", + HandlerType: (*MsgServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Swap", + Handler: _Msg_Swap_Handler, + }, + { + MethodName: "Redeem", + Handler: _Msg_Redeem_Handler, + }, + { + MethodName: "GovSetParams", + Handler: _Msg_GovSetParams_Handler, + }, + { + MethodName: "GovUpdateRegistry", + Handler: _Msg_GovUpdateRegistry_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "umee/metoken/v1/tx.proto", +} + +func (m *MsgSwap) 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 *MsgSwap) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSwap) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.MetokenDenom) > 0 { + i -= len(m.MetokenDenom) + copy(dAtA[i:], m.MetokenDenom) + i = encodeVarintTx(dAtA, i, uint64(len(m.MetokenDenom))) + i-- + dAtA[i] = 0x1a + } + { + size, err := m.Asset.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.User) > 0 { + i -= len(m.User) + copy(dAtA[i:], m.User) + i = encodeVarintTx(dAtA, i, uint64(len(m.User))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgSwapResponse) 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 *MsgSwapResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSwapResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Returned.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + { + size, err := m.Fee.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 *MsgRedeem) 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 *MsgRedeem) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgRedeem) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.AssetDenom) > 0 { + i -= len(m.AssetDenom) + copy(dAtA[i:], m.AssetDenom) + i = encodeVarintTx(dAtA, i, uint64(len(m.AssetDenom))) + i-- + dAtA[i] = 0x1a + } + { + size, err := m.Metoken.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.User) > 0 { + i -= len(m.User) + copy(dAtA[i:], m.User) + i = encodeVarintTx(dAtA, i, uint64(len(m.User))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgRedeemResponse) 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 *MsgRedeemResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgRedeemResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Fee.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + { + size, err := m.Returned.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 *MsgGovSetParams) 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 *MsgGovSetParams) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgGovSetParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Authority) > 0 { + i -= len(m.Authority) + copy(dAtA[i:], m.Authority) + i = encodeVarintTx(dAtA, i, uint64(len(m.Authority))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgGovSetParamsResponse) 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 *MsgGovSetParamsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgGovSetParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgGovUpdateRegistry) 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 *MsgGovUpdateRegistry) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgGovUpdateRegistry) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.UpdateIndex) > 0 { + for iNdEx := len(m.UpdateIndex) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.UpdateIndex[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.AddIndex) > 0 { + for iNdEx := len(m.AddIndex) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.AddIndex[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.Authority) > 0 { + i -= len(m.Authority) + copy(dAtA[i:], m.Authority) + i = encodeVarintTx(dAtA, i, uint64(len(m.Authority))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgGovUpdateRegistryResponse) 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 *MsgGovUpdateRegistryResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgGovUpdateRegistryResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func encodeVarintTx(dAtA []byte, offset int, v uint64) int { + offset -= sovTx(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgSwap) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.User) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.Asset.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.MetokenDenom) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgSwapResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Fee.Size() + n += 1 + l + sovTx(uint64(l)) + l = m.Returned.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgRedeem) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.User) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.Metoken.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.AssetDenom) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgRedeemResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Returned.Size() + n += 1 + l + sovTx(uint64(l)) + l = m.Fee.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgGovSetParams) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Authority) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.Params.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgGovSetParamsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgGovUpdateRegistry) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Authority) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if len(m.AddIndex) > 0 { + for _, e := range m.AddIndex { + l = e.Size() + n += 1 + l + sovTx(uint64(l)) + } + } + if len(m.UpdateIndex) > 0 { + for _, e := range m.UpdateIndex { + l = e.Size() + n += 1 + l + sovTx(uint64(l)) + } + } + return n +} + +func (m *MsgGovUpdateRegistryResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func sovTx(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTx(x uint64) (n int) { + return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgSwap) 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: MsgSwap: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSwap: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field User", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.User = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Asset", 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.Asset.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MetokenDenom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.MetokenDenom = string(dAtA[iNdEx:postIndex]) + 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 *MsgSwapResponse) 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: MsgSwapResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSwapResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Fee", 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.Fee.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Returned", 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.Returned.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 *MsgRedeem) 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: MsgRedeem: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRedeem: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field User", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.User = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Metoken", 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.Metoken.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AssetDenom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AssetDenom = string(dAtA[iNdEx:postIndex]) + 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 *MsgRedeemResponse) 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: MsgRedeemResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRedeemResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Returned", 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.Returned.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Fee", 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.Fee.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 *MsgGovSetParams) 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: MsgGovSetParams: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgGovSetParams: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Authority", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Authority = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", 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.Params.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 *MsgGovSetParamsResponse) 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: MsgGovSetParamsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgGovSetParamsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + 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 *MsgGovUpdateRegistry) 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: MsgGovUpdateRegistry: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgGovUpdateRegistry: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Authority", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Authority = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AddIndex", 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 + } + m.AddIndex = append(m.AddIndex, Index{}) + if err := m.AddIndex[len(m.AddIndex)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UpdateIndex", 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 + } + m.UpdateIndex = append(m.UpdateIndex, Index{}) + if err := m.UpdateIndex[len(m.UpdateIndex)-1].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 *MsgGovUpdateRegistryResponse) 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: MsgGovUpdateRegistryResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgGovUpdateRegistryResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + 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 skipTx(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTx + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTx + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTx + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTx = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTx = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTx = fmt.Errorf("proto: unexpected end of group") +)