From f88af02610a0e276c45e54a5d2663a79bdd6a8e5 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin <114929630+mtsitrin@users.noreply.github.com> Date: Fri, 27 Sep 2024 10:57:23 +0300 Subject: [PATCH] feat(iro): scale the bonding curve (#1247) --- app/keepers/keepers.go | 1 - ibctesting/genesis_transfer_test.go | 2 +- proto/dymensionxyz/dymension/iro/query.proto | 33 +- proto/dymensionxyz/dymension/iro/tx.proto | 8 +- x/iro/cli/query.go | 6 +- x/iro/cli/tx_trade.go | 22 +- x/iro/keeper/claim.go | 3 + x/iro/keeper/claim_test.go | 56 ++++ x/iro/keeper/create_plan.go | 14 +- x/iro/keeper/create_plan_test.go | 15 +- x/iro/keeper/keeper_test.go | 2 +- x/iro/keeper/query.go | 11 +- x/iro/keeper/settle.go | 30 +- x/iro/keeper/settle_test.go | 170 +++++++---- x/iro/keeper/trade.go | 10 +- x/iro/keeper/trade_test.go | 179 +++++++++-- x/iro/types/bonding_curve.go | 118 ++++++-- x/iro/types/bonding_curve_test.go | 270 ++++++++--------- x/iro/types/genesis_test.go | 3 +- x/iro/types/msgs.go | 21 +- x/iro/types/params.go | 2 +- x/iro/types/plan.go | 15 +- x/iro/types/query.pb.go | 300 +++++++++---------- x/iro/types/query.pb.gw.go | 28 +- x/iro/types/tx.pb.go | 137 ++++----- 25 files changed, 896 insertions(+), 560 deletions(-) create mode 100644 x/iro/keeper/claim_test.go diff --git a/app/keepers/keepers.go b/app/keepers/keepers.go index 4bf400af0..f71e3ae34 100644 --- a/app/keepers/keepers.go +++ b/app/keepers/keepers.go @@ -117,7 +117,6 @@ type AppKeepers struct { ParamsKeeper paramskeeper.Keeper IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly TransferStack ibcporttypes.IBCModule - ICS4Wrapper ibcporttypes.ICS4Wrapper delayedAckMiddleware *delayedackmodule.IBCMiddleware EvidenceKeeper evidencekeeper.Keeper TransferKeeper ibctransferkeeper.Keeper diff --git a/ibctesting/genesis_transfer_test.go b/ibctesting/genesis_transfer_test.go index 62dc219b6..7c6518346 100644 --- a/ibctesting/genesis_transfer_test.go +++ b/ibctesting/genesis_transfer_test.go @@ -80,7 +80,7 @@ func (s *transferGenesisSuite) TestNoIRO() { // In this case, the genesis transfer is required // regular transfers should fail until the genesis transfer is done func (s *transferGenesisSuite) TestIRO() { - amt := math.NewIntFromUint64(10000000000000000000) + amt := math.NewIntFromUint64(1_000_000).MulRaw(1e18) rollapp := s.hubApp().RollappKeeper.MustGetRollapp(s.hubCtx(), rollappChainID()) denom := rollapp.GenesisInfo.NativeDenom.Base diff --git a/proto/dymensionxyz/dymension/iro/query.proto b/proto/dymensionxyz/dymension/iro/query.proto index 6ea1e21cb..50f6f5646 100644 --- a/proto/dymensionxyz/dymension/iro/query.proto +++ b/proto/dymensionxyz/dymension/iro/query.proto @@ -9,44 +9,44 @@ import "cosmos/base/v1beta1/coin.proto"; option go_package = "github.com/dymensionxyz/dymension/v3/x/iro/types"; -// Query defines the gRPC querier service. +// Query defines the gRPC querier service for the IRO module. service Query { - // Param queries the parameters of the module. + // Params queries the parameters of the IRO module. rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { option (google.api.http).get = "/dymensionxyz/dymension/iro/params"; } - // Plans + // QueryPlans retrieves all available plans. rpc QueryPlans(QueryPlansRequest) returns (QueryPlansResponse) { option (google.api.http).get = "/dymensionxyz/dymension/iro/plans"; } - // Plan returns the plan for the specified plan ID. + // QueryPlan retrieves the plan for the specified plan ID. rpc QueryPlan(QueryPlanRequest) returns (QueryPlanResponse) { option (google.api.http).get = "/dymensionxyz/dymension/iro/plans/{plan_id}"; } - // PlanByRollapp returns the plans for the specified rollapp ID. + // QueryPlanByRollapp retrieves the plans for the specified rollapp ID. rpc QueryPlanByRollapp(QueryPlanByRollappRequest) returns (QueryPlanByRollappResponse) { option (google.api.http).get = "/dymensionxyz/dymension/iro/plans_by_rollapp/{rollapp_id}"; } - // Price returns the current price for 1 IRO token for the specified plan ID. - rpc QueryPrice(QueryPriceRequest) returns (QueryPriceResponse) { + // QuerySpotPrice retrieves the current spot price for the specified plan ID. + // The result is the price of 1 IRO token (not iro's base denom) + rpc QuerySpotPrice(QuerySpotPriceRequest) returns (QuerySpotPriceResponse) { option (google.api.http).get = "/dymensionxyz/dymension/iro/price/{plan_id}"; } - // Cost returns the expected cost for buying or selling the specified amount - // of shares. + // QueryCost retrieves the expected cost for buying or selling the specified amount of shares. rpc QueryCost(QueryCostRequest) returns (QueryCostResponse) { option (google.api.http).get = "/dymensionxyz/dymension/iro/cost/{plan_id}"; } - // Claimed returns the claimed amount thus far for the specified plan ID. + // QueryClaimed retrieves the claimed amount thus far for the specified plan ID. rpc QueryClaimed(QueryClaimedRequest) returns (QueryClaimedResponse) { option (google.api.http).get = "/dymensionxyz/dymension/iro/claimed/{plan_id}"; @@ -84,11 +84,16 @@ message QueryPlanByRollappRequest { string rollapp_id = 1; } // Query/QueryPlanByRollapp RPC method. message QueryPlanByRollappResponse { Plan plan = 1; } -// QueryPriceRequest is the request type for the Query/QueryPrice RPC method. -message QueryPriceRequest { string plan_id = 1; } +// QuerySpotPriceRequest is the request type for the Query/QuerySpotPrice RPC method. +message QuerySpotPriceRequest { string plan_id = 1; } -// QueryPriceResponse is the response type for the Query/QueryPrice RPC method. -message QueryPriceResponse { cosmos.base.v1beta1.Coin price = 1; } +// QuerySpotPriceResponse is the response type for the Query/QuerySpotPrice RPC method. +message QuerySpotPriceResponse { + string price = 1 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; +} // QueryCostRequest is the request type for the Query/QueryCost RPC method. message QueryCostRequest { diff --git a/proto/dymensionxyz/dymension/iro/tx.proto b/proto/dymensionxyz/dymension/iro/tx.proto index 0aa82ddd1..78b2af24d 100644 --- a/proto/dymensionxyz/dymension/iro/tx.proto +++ b/proto/dymensionxyz/dymension/iro/tx.proto @@ -93,8 +93,8 @@ message MsgBuy { (gogoproto.nullable) = false ]; - // The expected output amount. - string expected_out_amount = 4 [ + // The maximum cost this buy action can incur. + string max_cost_amount = 4 [ (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", (gogoproto.nullable) = false ]; @@ -117,8 +117,8 @@ message MsgSell { (gogoproto.nullable) = false ]; - // The expected output amount. - string expected_out_amount = 4 [ + // The minimum income this sell action can incur. + string min_income_amount = 4 [ (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", (gogoproto.nullable) = false ]; diff --git a/x/iro/cli/query.go b/x/iro/cli/query.go index 7de92e4aa..cc0374ab1 100644 --- a/x/iro/cli/query.go +++ b/x/iro/cli/query.go @@ -26,7 +26,7 @@ func GetQueryCmd() *cobra.Command { CmdQueryPlans(), CmdQueryPlan(), CmdQueryPlanByRollapp(), - CmdQueryPrice(), + CmdQuerySpotPrice(), CmdQueryCost(), CmdQueryClaimed(), ) @@ -109,7 +109,7 @@ func CmdQueryPlanByRollapp() *cobra.Command { return cmd } -func CmdQueryPrice() *cobra.Command { +func CmdQuerySpotPrice() *cobra.Command { cmd := &cobra.Command{ Use: "price [plan-id]", Short: "Query the current price for 1 IRO token for a specific IRO plan", @@ -121,7 +121,7 @@ func CmdQueryPrice() *cobra.Command { } queryClient := types.NewQueryClient(clientCtx) - res, err := queryClient.QueryPrice(cmd.Context(), &types.QueryPriceRequest{PlanId: args[0]}) + res, err := queryClient.QuerySpotPrice(cmd.Context(), &types.QuerySpotPriceRequest{PlanId: args[0]}) if err != nil { return err } diff --git a/x/iro/cli/tx_trade.go b/x/iro/cli/tx_trade.go index 38c7f7bf0..98a7aa356 100644 --- a/x/iro/cli/tx_trade.go +++ b/x/iro/cli/tx_trade.go @@ -42,32 +42,32 @@ func createBuySellCmd(use string, short string, isBuy bool) *cobra.Command { planID := args[0] argAmount := args[1] - argExpectedOutAmount := args[2] + argExpectedAmount := args[2] amount, ok := math.NewIntFromString(argAmount) if !ok { return fmt.Errorf("invalid amount: %s", argAmount) } - expectedOutAmount, ok := math.NewIntFromString(argExpectedOutAmount) + expectedAmount, ok := math.NewIntFromString(argExpectedAmount) if !ok { - return fmt.Errorf("invalid expected out amount: %s", argExpectedOutAmount) + return fmt.Errorf("invalid expected out amount: %s", argExpectedAmount) } var msg sdk.Msg if isBuy { msg = &types.MsgBuy{ - Buyer: clientCtx.GetFromAddress().String(), - PlanId: planID, - Amount: amount, - ExpectedOutAmount: expectedOutAmount, + Buyer: clientCtx.GetFromAddress().String(), + PlanId: planID, + Amount: amount, + MaxCostAmount: expectedAmount, } } else { msg = &types.MsgSell{ - Seller: clientCtx.GetFromAddress().String(), - PlanId: planID, - Amount: amount, - ExpectedOutAmount: expectedOutAmount, + Seller: clientCtx.GetFromAddress().String(), + PlanId: planID, + Amount: amount, + MinIncomeAmount: expectedAmount, } } diff --git a/x/iro/keeper/claim.go b/x/iro/keeper/claim.go index c475bb30e..6560e03c6 100644 --- a/x/iro/keeper/claim.go +++ b/x/iro/keeper/claim.go @@ -20,6 +20,9 @@ func (m msgServer) Claim(ctx context.Context, req *types.MsgClaim) (*types.MsgCl } // Claim claims the FUT token for the real RA token +// +// This function allows a user to claim their RA tokens by burning their FUT tokens. +// It burns *all* the FUT tokens the claimer has, and sends the equivalent amount of RA tokens to the claimer. func (k Keeper) Claim(ctx sdk.Context, planId string, claimer sdk.AccAddress) error { plan, found := k.GetPlan(ctx, planId) if !found { diff --git a/x/iro/keeper/claim_test.go b/x/iro/keeper/claim_test.go new file mode 100644 index 000000000..b61a350f1 --- /dev/null +++ b/x/iro/keeper/claim_test.go @@ -0,0 +1,56 @@ +package keeper_test + +import ( + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/dymensionxyz/dymension/v3/testutil/sample" + "github.com/dymensionxyz/dymension/v3/x/iro/types" +) + +func (s *KeeperTestSuite) TestClaim() { + rollappId := s.CreateDefaultRollapp() + k := s.App.IROKeeper + curve := types.DefaultBondingCurve() + incentives := types.DefaultIncentivePlanParams() + rollappDenom := "dasdasdasdasdsa" + + startTime := time.Now() + amt := sdk.NewInt(1_000_000).MulRaw(1e18) + + rollapp, _ := s.App.RollappKeeper.GetRollapp(s.Ctx, rollappId) + planId, err := k.CreatePlan(s.Ctx, amt, startTime, startTime.Add(time.Hour), rollapp, curve, incentives) + s.Require().NoError(err) + planDenom := k.MustGetPlan(s.Ctx, planId).TotalAllocation.Denom + balance := s.App.BankKeeper.GetBalance(s.Ctx, k.AK.GetModuleAddress(types.ModuleName), planDenom) + s.Require().Equal(amt, balance.Amount) + + claimer := sample.Acc() + // buy some tokens + s.Ctx = s.Ctx.WithBlockTime(startTime.Add(time.Minute)) + soldAmt := sdk.NewInt(1_000).MulRaw(1e18) + s.BuySomeTokens(planId, claimer, soldAmt) + + // claim should fail as not settled + err = k.Claim(s.Ctx, planId, claimer) + s.Require().Error(err) + + // settle + s.FundModuleAcc(types.ModuleName, sdk.NewCoins(sdk.NewCoin(rollappDenom, amt))) + err = k.Settle(s.Ctx, rollappId, rollappDenom) + s.Require().NoError(err) + + // claim should fail as no balance available (random address) + err = k.Claim(s.Ctx, planId, sample.Acc()) + s.Require().Error(err) + + // fund. claim should succeed + err = k.Claim(s.Ctx, planId, claimer) + s.Require().NoError(err) + + // assert claimed amt + balance = s.App.BankKeeper.GetBalance(s.Ctx, k.AK.GetModuleAddress(types.ModuleName), planDenom) + s.Require().True(balance.IsZero()) + balance = s.App.BankKeeper.GetBalance(s.Ctx, claimer, rollappDenom) + s.Require().Equal(soldAmt, balance.Amount) +} diff --git a/x/iro/keeper/create_plan.go b/x/iro/keeper/create_plan.go index 328e09c20..999bf86fb 100644 --- a/x/iro/keeper/create_plan.go +++ b/x/iro/keeper/create_plan.go @@ -21,7 +21,8 @@ import ( ) // This function is used to create a new plan for a rollapp. -// Validations on the request: +// Non stateful validation happens on the req.ValidateBasic() method +// Stateful validations on the request: // - The rollapp must exist, with no IRO plan // - The rollapp must be owned by the creator of the plan // - The rollapp PreLaunchTime must be in the future @@ -74,6 +75,13 @@ func (m msgServer) CreatePlan(goCtx context.Context, req *types.MsgCreatePlan) ( } // CreatePlan creates a new IRO plan for a rollapp +// This function performs the following steps: +// 1. Sets the IRO plan to the rollapp with the specified pre-launch time. +// 2. Mints the allocated amount of tokens for the rollapp. +// 3. Creates a new plan with the provided parameters and validates it. +// 4. Creates a new module account for the IRO plan. +// 5. Charges the creation fee from the rollapp owner to the plan's module account. +// 6. Stores the plan in the keeper. func (k Keeper) CreatePlan(ctx sdk.Context, allocatedAmount math.Int, start, preLaunchTime time.Time, rollapp rollapptypes.Rollapp, curve types.BondingCurve, incentivesParams types.IncentivePlanParams) (string, error) { err := k.rk.SetIROPlanToRollapp(ctx, &rollapp, preLaunchTime) if err != nil { @@ -86,6 +94,10 @@ func (k Keeper) CreatePlan(ctx sdk.Context, allocatedAmount math.Int, start, pre } plan := types.NewPlan(k.GetNextPlanIdAndIncrement(ctx), rollapp.RollappId, allocation, curve, start, preLaunchTime, incentivesParams) + if err := plan.ValidateBasic(); err != nil { + return "", errors.Join(gerrc.ErrInvalidArgument, err) + } + // Create a new module account for the IRO plan _, err = k.CreateModuleAccountForPlan(ctx, plan) if err != nil { diff --git a/x/iro/keeper/create_plan_test.go b/x/iro/keeper/create_plan_test.go index b8c9d81fc..e964f7fbe 100644 --- a/x/iro/keeper/create_plan_test.go +++ b/x/iro/keeper/create_plan_test.go @@ -15,25 +15,27 @@ func (s *KeeperTestSuite) TestValidateRollappPreconditions_MissingGenesisInfo() curve := types.DefaultBondingCurve() incentives := types.DefaultIncentivePlanParams() + allocation := sdk.NewInt(100).MulRaw(1e18) + rollapp, _ := s.App.RollappKeeper.GetRollapp(s.Ctx, rollappId) // test missing genesis checksum rollapp.GenesisInfo.GenesisChecksum = "" s.App.RollappKeeper.SetRollapp(s.Ctx, rollapp) - _, err := k.CreatePlan(s.Ctx, sdk.NewInt(100), time.Now(), time.Now().Add(time.Hour), rollapp, curve, incentives) + _, err := k.CreatePlan(s.Ctx, allocation, time.Now(), time.Now().Add(time.Hour), rollapp, curve, incentives) s.Require().Error(err) // test already launched rollapp.GenesisInfo.GenesisChecksum = "aaaaaa" rollapp.Launched = true s.App.RollappKeeper.SetRollapp(s.Ctx, rollapp) - _, err = k.CreatePlan(s.Ctx, sdk.NewInt(100), time.Now(), time.Now().Add(time.Hour), rollapp, curve, incentives) + _, err = k.CreatePlan(s.Ctx, allocation, time.Now(), time.Now().Add(time.Hour), rollapp, curve, incentives) s.Require().Error(err) rollapp.Launched = false // add check for happy path s.App.RollappKeeper.SetRollapp(s.Ctx, rollapp) - _, err = k.CreatePlan(s.Ctx, sdk.NewInt(100), time.Now(), time.Now().Add(time.Hour), rollapp, curve, incentives) + _, err = k.CreatePlan(s.Ctx, allocation, time.Now(), time.Now().Add(time.Hour), rollapp, curve, incentives) s.Require().NoError(err) } @@ -44,18 +46,19 @@ func (s *KeeperTestSuite) TestCreatePlan() { k := s.App.IROKeeper curve := types.DefaultBondingCurve() incentives := types.DefaultIncentivePlanParams() + allocation := sdk.NewInt(100).MulRaw(1e18) rollapp, _ := s.App.RollappKeeper.GetRollapp(s.Ctx, rollappId) - planId, err := k.CreatePlan(s.Ctx, sdk.NewInt(100), time.Now(), time.Now().Add(time.Hour), rollapp, curve, incentives) + planId, err := k.CreatePlan(s.Ctx, allocation, time.Now(), time.Now().Add(time.Hour), rollapp, curve, incentives) s.Require().NoError(err) // creating a a plan for same rollapp should fail - _, err = k.CreatePlan(s.Ctx, sdk.NewInt(100), time.Now(), time.Now().Add(time.Hour), rollapp, curve, incentives) + _, err = k.CreatePlan(s.Ctx, allocation, time.Now(), time.Now().Add(time.Hour), rollapp, curve, incentives) s.Require().Error(err) // create plan for different rollappID. test last planId increases rollapp2, _ := s.App.RollappKeeper.GetRollapp(s.Ctx, rollappId2) - planId2, err := k.CreatePlan(s.Ctx, sdk.NewInt(100), time.Now(), time.Now().Add(time.Hour), rollapp2, curve, incentives) + planId2, err := k.CreatePlan(s.Ctx, allocation, time.Now(), time.Now().Add(time.Hour), rollapp2, curve, incentives) s.Require().NoError(err) s.Require().Greater(planId2, planId) diff --git a/x/iro/keeper/keeper_test.go b/x/iro/keeper/keeper_test.go index e6629dc01..90f7d8b79 100644 --- a/x/iro/keeper/keeper_test.go +++ b/x/iro/keeper/keeper_test.go @@ -48,7 +48,7 @@ func (suite *KeeperTestSuite) SetupTest() { // BuySomeTokens buys some tokens from the plan func (suite *KeeperTestSuite) BuySomeTokens(planId string, buyer sdk.AccAddress, amt math.Int) { - maxAmt := sdk.NewInt(1_000_000_000) + maxAmt := sdk.NewInt(1_000_000_000).MulRaw(1e18) suite.FundAcc(buyer, sdk.NewCoins(sdk.NewCoin("adym", amt.MulRaw(10)))) // 10 times the amount to buy, for buffer and fees err := suite.App.IROKeeper.Buy(suite.Ctx, planId, buyer, amt, maxAmt) suite.Require().NoError(err) diff --git a/x/iro/keeper/query.go b/x/iro/keeper/query.go index 988d55120..7016cf719 100644 --- a/x/iro/keeper/query.go +++ b/x/iro/keeper/query.go @@ -104,8 +104,8 @@ func (k Keeper) QueryPlans(goCtx context.Context, req *types.QueryPlansRequest) return &types.QueryPlansResponse{Plans: k.GetAllPlans(ctx)}, nil } -// QueryPrice implements types.QueryServer. -func (k Keeper) QueryPrice(goCtx context.Context, req *types.QueryPriceRequest) (*types.QueryPriceResponse, error) { +// QuerySpotPrice implements types.QueryServer. +func (k Keeper) QuerySpotPrice(goCtx context.Context, req *types.QuerySpotPriceRequest) (*types.QuerySpotPriceResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "invalid request") } @@ -116,10 +116,7 @@ func (k Keeper) QueryPrice(goCtx context.Context, req *types.QueryPriceRequest) return nil, status.Error(codes.NotFound, "plan not found") } - price := plan.BondingCurve.SpotPrice(plan.SoldAmt).TruncateInt() - coin := sdk.NewCoin(appparams.BaseDenom, price) - - return &types.QueryPriceResponse{ - Price: &coin, + return &types.QuerySpotPriceResponse{ + Price: plan.SpotPrice(), }, nil } diff --git a/x/iro/keeper/settle.go b/x/iro/keeper/settle.go index c9a47697d..18ff5a608 100644 --- a/x/iro/keeper/settle.go +++ b/x/iro/keeper/settle.go @@ -23,6 +23,12 @@ func (k Keeper) AfterTransfersEnabled(ctx sdk.Context, rollappId, rollappIBCDeno } // Settle settles the iro plan with the given rollappId +// +// This function performs the following steps: +// - Validates that the "TotalAllocation.Amount" of the RA token are available in the module account. +// - Burns any unsold FUT tokens in the module account. +// - Marks the plan as settled, allowing users to claim tokens. +// - Uses the raised DYM and unsold tokens to bootstrap the rollapp's liquidity pool. func (k Keeper) Settle(ctx sdk.Context, rollappId, rollappIBCDenom string) error { plan, found := k.GetPlanByRollapp(ctx, rollappId) if !found { @@ -69,7 +75,13 @@ func (k Keeper) Settle(ctx sdk.Context, rollappId, rollappIBCDenom string) error return nil } -// Bootstrap liquidity pool with the raised DYM and unsold tokens +// bootstrapLiquidityPool bootstraps the liquidity pool with the raised DYM and unsold tokens. +// +// This function performs the following steps: +// - Sends the raised DYM to the IRO module to be used as the pool creator. +// - Determines the required pool liquidity amounts to fulfill the last price. +// - Creates a balancer pool with the determined tokens and DYM. +// - Uses leftover tokens as incentives to the pool LP token holders. func (k Keeper) bootstrapLiquidityPool(ctx sdk.Context, plan types.Plan) error { unallocatedTokens := plan.TotalAllocation.Amount.Sub(plan.SoldAmt) // assumed > 0, as we enforce it in the Buy function raisedDYM := k.BK.GetBalance(ctx, plan.GetAddress(), appparams.BaseDenom) // assumed > 0, as we enforce it by IRO creation fee @@ -80,10 +92,8 @@ func (k Keeper) bootstrapLiquidityPool(ctx sdk.Context, plan types.Plan) error { return err } - // calculate last price - lastPrice := plan.BondingCurve.SpotPrice(plan.SoldAmt) // find the tokens needed to bootstrap the pool, to fulfill last price - tokens, dym := determineLimitingFactor(unallocatedTokens, raisedDYM.Amount, lastPrice) + tokens, dym := calcLiquidityPoolTokens(unallocatedTokens, raisedDYM.Amount, plan.SpotPrice()) rollappLiquidityCoin := sdk.NewCoin(plan.SettledDenom, tokens) dymLiquidityCoin := sdk.NewCoin(appparams.BaseDenom, dym) @@ -126,14 +136,18 @@ func (k Keeper) bootstrapLiquidityPool(ctx sdk.Context, plan types.Plan) error { return nil } -func determineLimitingFactor(unsoldRATokens, raisedDYM math.Int, settledIROPrice math.LegacyDec) (RATokens, dym math.Int) { - requiredDYM := unsoldRATokens.ToLegacyDec().Mul(settledIROPrice).TruncateInt() +// calcLiquidityPoolTokens determines the tokens and DYM to be used for bootstrapping the liquidity pool. +// +// This function calculates the required DYM based on the settled token price and compares it with the raised DYM. +// It returns the amount of RA tokens and DYM to be used for bootstrapping the liquidity pool so it fulfills the last price. +func calcLiquidityPoolTokens(unsoldRATokens, raisedDYM math.Int, settledTokenPrice math.LegacyDec) (RATokens, dym math.Int) { + requiredDYM := settledTokenPrice.MulInt(unsoldRATokens).TruncateInt() // if raisedDYM is less than requiredDYM, than DYM is the limiting factor // we use all the raisedDYM, and the corresponding amount of tokens if raisedDYM.LT(requiredDYM) { dym = raisedDYM - RATokens = raisedDYM.ToLegacyDec().Quo(settledIROPrice).TruncateInt() + RATokens = raisedDYM.ToLegacyDec().Quo(settledTokenPrice).TruncateInt() } else { // if raisedDYM is more than requiredDYM, than tokens are the limiting factor // we use all the unsold tokens, and the corresponding amount of DYM @@ -141,7 +155,7 @@ func determineLimitingFactor(unsoldRATokens, raisedDYM math.Int, settledIROPrice dym = requiredDYM } - // for the extreme edge case where required liquidity truncated to 0 + // for the edge cases where required liquidity truncated to 0 // we use what we have as it guaranteed to be more than 0 if dym.IsZero() { dym = raisedDYM diff --git a/x/iro/keeper/settle_test.go b/x/iro/keeper/settle_test.go index 39db27f62..dd17851bc 100644 --- a/x/iro/keeper/settle_test.go +++ b/x/iro/keeper/settle_test.go @@ -3,6 +3,7 @@ package keeper_test import ( "time" + "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" gammtypes "github.com/osmosis-labs/osmosis/v15/x/gamm/types" @@ -10,6 +11,7 @@ import ( appparams "github.com/dymensionxyz/dymension/v3/app/params" "github.com/dymensionxyz/dymension/v3/testutil/sample" incentivestypes "github.com/dymensionxyz/dymension/v3/x/incentives/types" + keeper "github.com/dymensionxyz/dymension/v3/x/iro/keeper" "github.com/dymensionxyz/dymension/v3/x/iro/types" ) @@ -21,7 +23,7 @@ func (s *KeeperTestSuite) TestSettle() { startTime := time.Now() endTime := startTime.Add(time.Hour) - amt := sdk.NewInt(1_000_000) + amt := sdk.NewInt(1_000_000).MulRaw(1e18) rollappDenom := "dasdasdasdasdsa" rollapp := s.App.RollappKeeper.MustGetRollapp(s.Ctx, rollappId) @@ -35,7 +37,7 @@ func (s *KeeperTestSuite) TestSettle() { // buy some tokens s.Ctx = s.Ctx.WithBlockTime(startTime.Add(time.Minute)) - soldAmt := sdk.NewInt(1_000) + soldAmt := sdk.NewInt(1_000).MulRaw(1e18) s.BuySomeTokens(planId, sample.Acc(), soldAmt) // settle should fail as no rollappDenom balance available @@ -60,53 +62,6 @@ func (s *KeeperTestSuite) TestSettle() { s.Require().Equal(soldAmt, balance.Amount) } -func (s *KeeperTestSuite) TestClaim() { - rollappId := s.CreateDefaultRollapp() - k := s.App.IROKeeper - curve := types.DefaultBondingCurve() - incentives := types.DefaultIncentivePlanParams() - rollappDenom := "dasdasdasdasdsa" - - startTime := time.Now() - amt := sdk.NewInt(1_000_000) - - rollapp, _ := s.App.RollappKeeper.GetRollapp(s.Ctx, rollappId) - planId, err := k.CreatePlan(s.Ctx, amt, startTime, startTime.Add(time.Hour), rollapp, curve, incentives) - s.Require().NoError(err) - planDenom := k.MustGetPlan(s.Ctx, planId).TotalAllocation.Denom - balance := s.App.BankKeeper.GetBalance(s.Ctx, k.AK.GetModuleAddress(types.ModuleName), planDenom) - s.Require().Equal(amt, balance.Amount) - - claimer := sample.Acc() - // buy some tokens - s.Ctx = s.Ctx.WithBlockTime(startTime.Add(time.Minute)) - soldAmt := sdk.NewInt(1_000) - s.BuySomeTokens(planId, claimer, soldAmt) - - // claim should fail as not settled - err = k.Claim(s.Ctx, planId, claimer) - s.Require().Error(err) - - // settle - s.FundModuleAcc(types.ModuleName, sdk.NewCoins(sdk.NewCoin(rollappDenom, amt))) - err = k.Settle(s.Ctx, rollappId, rollappDenom) - s.Require().NoError(err) - - // claim should fail as no balance available (random address) - err = k.Claim(s.Ctx, planId, sample.Acc()) - s.Require().Error(err) - - // fund. claim should succeed - err = k.Claim(s.Ctx, planId, claimer) - s.Require().NoError(err) - - // assert claimed amt - balance = s.App.BankKeeper.GetBalance(s.Ctx, k.AK.GetModuleAddress(types.ModuleName), planDenom) - s.Require().True(balance.IsZero()) - balance = s.App.BankKeeper.GetBalance(s.Ctx, claimer, rollappDenom) - s.Require().Equal(soldAmt, balance.Amount) -} - // Test liquidity pool bootstrap func (s *KeeperTestSuite) TestBootstrapLiquidityPool() { rollappId := s.CreateDefaultRollapp() @@ -115,31 +70,32 @@ func (s *KeeperTestSuite) TestBootstrapLiquidityPool() { incentives := types.DefaultIncentivePlanParams() startTime := time.Now() - amt := sdk.NewInt(1_000_000) + allocation := sdk.NewInt(1_000_000).MulRaw(1e18) + maxAmt := sdk.NewInt(1_000_000_000).MulRaw(1e18) rollappDenom := "dasdasdasdasdsa" rollapp := s.App.RollappKeeper.MustGetRollapp(s.Ctx, rollappId) // create IRO plan apptesting.FundAccount(s.App, s.Ctx, sdk.MustAccAddressFromBech32(rollapp.Owner), sdk.NewCoins(sdk.NewCoin(appparams.BaseDenom, k.GetParams(s.Ctx).CreationFee))) - planId, err := k.CreatePlan(s.Ctx, amt, startTime, startTime.Add(time.Hour), rollapp, curve, incentives) + planId, err := k.CreatePlan(s.Ctx, allocation, startTime, startTime.Add(time.Hour), rollapp, curve, incentives) s.Require().NoError(err) // buy some tokens s.Ctx = s.Ctx.WithBlockTime(startTime.Add(time.Minute)) buyer := sample.Acc() - buyersFunds := sdk.NewCoins(sdk.NewCoin("adym", sdk.NewInt(100_000))) + buyersFunds := sdk.NewCoins(sdk.NewCoin("adym", maxAmt)) s.FundAcc(buyer, buyersFunds) - err = k.Buy(s.Ctx, planId, buyer, sdk.NewInt(1_000), sdk.NewInt(100_000)) + err = k.Buy(s.Ctx, planId, buyer, sdk.NewInt(1_000).MulRaw(1e18), maxAmt) s.Require().NoError(err) plan := k.MustGetPlan(s.Ctx, planId) raisedDYM := k.BK.GetBalance(s.Ctx, plan.GetAddress(), appparams.BaseDenom) - preSettleCoins := sdk.NewCoins(raisedDYM, sdk.NewCoin(rollappDenom, amt.Sub(plan.SoldAmt))) + preSettleCoins := sdk.NewCoins(raisedDYM, sdk.NewCoin(rollappDenom, allocation.Sub(plan.SoldAmt))) // settle should succeed after fund - s.FundModuleAcc(types.ModuleName, sdk.NewCoins(sdk.NewCoin(rollappDenom, amt))) + s.FundModuleAcc(types.ModuleName, sdk.NewCoins(sdk.NewCoin(rollappDenom, allocation))) err = k.Settle(s.Ctx, rollappId, rollappDenom) s.Require().NoError(err) @@ -154,7 +110,7 @@ func (s *KeeperTestSuite) TestBootstrapLiquidityPool() { s.Require().NoError(err) plan = k.MustGetPlan(s.Ctx, planId) - lastPrice := plan.BondingCurve.SpotPrice(plan.SoldAmt) + lastPrice := plan.SpotPrice() s.Require().Equal(lastPrice, price) // assert incentives @@ -179,4 +135,104 @@ func (s *KeeperTestSuite) TestBootstrapLiquidityPool() { s.Assert().Equal(expectedIncentives, gauge.Coins) } -// test edge cases: nothing sold, all sold +func (s *KeeperTestSuite) TestSettleNothingSold() { + rollappId := s.CreateDefaultRollapp() + k := s.App.IROKeeper + curve := types.DefaultBondingCurve() + incentives := types.DefaultIncentivePlanParams() + + startTime := time.Now() + endTime := startTime.Add(time.Hour) + amt := sdk.NewInt(1_000_000).MulRaw(1e18) + rollappDenom := "rollapp_denom" + + rollapp := s.App.RollappKeeper.MustGetRollapp(s.Ctx, rollappId) + _, err := k.CreatePlan(s.Ctx, amt, startTime, endTime, rollapp, curve, incentives) + s.Require().NoError(err) + // planDenom := k.MustGetPlan(s.Ctx, planId).TotalAllocation.Denom + + // Settle without any tokens sold + s.Ctx = s.Ctx.WithBlockTime(endTime.Add(time.Minute)) + s.FundModuleAcc(types.ModuleName, sdk.NewCoins(sdk.NewCoin(rollappDenom, amt))) + err = k.Settle(s.Ctx, rollappId, rollappDenom) + s.Require().NoError(err) + + /* -------------------------- assert liquidity pool ------------------------- */ + // pool created + expectedPoolID := uint64(1) + pool, err := s.App.GAMMKeeper.GetPool(s.Ctx, expectedPoolID) + s.Require().NoError(err) + poolCoins := pool.GetTotalPoolLiquidity(s.Ctx) + poolCoins.AmountOf("adym").Equal(s.App.IROKeeper.GetParams(s.Ctx).CreationFee) + + // incentives expected to have zero coins + gauges, err := s.App.IncentivesKeeper.GetGaugesForDenom(s.Ctx, gammtypes.GetPoolShareDenom(expectedPoolID)) + s.Require().NoError(err) + found := false + gauge := incentivestypes.Gauge{} + for _, gauge = range gauges { + if !gauge.IsPerpetual { + found = true + break + } + } + s.Require().True(found) + s.Require().True(gauge.Coins.IsZero()) +} + +func (s *KeeperTestSuite) TestSettleAllSold() { + rollappId := s.CreateDefaultRollapp() + k := s.App.IROKeeper + // setting curve with fixed price + curve := types.BondingCurve{ + M: math.LegacyMustNewDecFromStr("0"), + N: math.LegacyMustNewDecFromStr("1"), + C: math.LegacyMustNewDecFromStr("0.00001"), + } + incentives := types.DefaultIncentivePlanParams() + + startTime := time.Now() + endTime := startTime.Add(time.Hour) + amt := sdk.NewInt(1_000_000).MulRaw(1e18) + rollappDenom := "rollapp_denom" + + rollapp := s.App.RollappKeeper.MustGetRollapp(s.Ctx, rollappId) + planId, err := k.CreatePlan(s.Ctx, amt, startTime, endTime, rollapp, curve, incentives) + s.Require().NoError(err) + + // Buy all possible tokens + s.Ctx = s.Ctx.WithBlockTime(startTime.Add(time.Minute)) + buyer := sample.Acc() + buyAmt := amt.ToLegacyDec().Mul(keeper.AllocationSellLimit).TruncateInt() + s.BuySomeTokens(planId, buyer, buyAmt) + + // Settle + s.Ctx = s.Ctx.WithBlockTime(endTime.Add(time.Minute)) + s.FundModuleAcc(types.ModuleName, sdk.NewCoins(sdk.NewCoin(rollappDenom, amt))) + err = k.Settle(s.Ctx, rollappId, rollappDenom) + s.Require().NoError(err) + + plan := k.MustGetPlan(s.Ctx, planId) + + pool, err := s.App.GAMMKeeper.GetPool(s.Ctx, 1) + s.Require().NoError(err) + + gauges, err := s.App.IncentivesKeeper.GetGaugesForDenom(s.Ctx, gammtypes.GetPoolShareDenom(1)) + s.Require().NoError(err) + found := false + gauge := incentivestypes.Gauge{} + for _, gauge = range gauges { + if !gauge.IsPerpetual { + found = true + break + } + } + s.Require().True(found) + + // only few RA tokens left, so the pool should be quite small + // most of the dym should be as incentive + s.T().Log("Pool coins", pool.GetTotalPoolLiquidity(s.Ctx)) + s.T().Log("Gauge coins", gauge.Coins) + s.Require().True(pool.GetTotalPoolLiquidity(s.Ctx).AmountOf("adym").LT(gauge.Coins.AmountOf("adym"))) + s.Require().Equal(pool.GetTotalPoolLiquidity(s.Ctx).AmountOf(plan.SettledDenom), amt.Sub(buyAmt)) +} diff --git a/x/iro/keeper/trade.go b/x/iro/keeper/trade.go index ce3dd128c..4c0363cf7 100644 --- a/x/iro/keeper/trade.go +++ b/x/iro/keeper/trade.go @@ -23,7 +23,7 @@ func (m msgServer) Buy(ctx context.Context, req *types.MsgBuy) (*types.MsgBuyRes return nil, err } - err = m.Keeper.Buy(sdk.UnwrapSDKContext(ctx), req.PlanId, buyer, req.Amount, req.ExpectedOutAmount) + err = m.Keeper.Buy(sdk.UnwrapSDKContext(ctx), req.PlanId, buyer, req.Amount, req.MaxCostAmount) if err != nil { return nil, err } @@ -37,7 +37,7 @@ func (m msgServer) Sell(ctx context.Context, req *types.MsgSell) (*types.MsgSell if err != nil { return nil, err } - err = m.Keeper.Sell(sdk.UnwrapSDKContext(ctx), req.PlanId, seller, req.Amount, req.ExpectedOutAmount) + err = m.Keeper.Sell(sdk.UnwrapSDKContext(ctx), req.PlanId, seller, req.Amount, req.MinIncomeAmount) if err != nil { return nil, err } @@ -108,7 +108,7 @@ func (k Keeper) Buy(ctx sdk.Context, planId string, buyer sdk.AccAddress, amount } // Sell sells allocation with price according to the price curve -func (k Keeper) Sell(ctx sdk.Context, planId string, seller sdk.AccAddress, amountTokensToSell, minCostAmt math.Int) error { +func (k Keeper) Sell(ctx sdk.Context, planId string, seller sdk.AccAddress, amountTokensToSell, minIncomeAmt math.Int) error { plan, err := k.GetTradeableIRO(ctx, planId, seller.String()) if err != nil { return err @@ -122,8 +122,8 @@ func (k Keeper) Sell(ctx sdk.Context, planId string, seller sdk.AccAddress, amou } // Validate expected out amount - if costMinusTakerFee.Amount.LT(minCostAmt) { - return errorsmod.Wrapf(types.ErrInvalidMinCost, "minCost: %s, cost: %s, fee: %s", minCostAmt.String(), cost.String(), takerFee.String()) + if costMinusTakerFee.Amount.LT(minIncomeAmt) { + return errorsmod.Wrapf(types.ErrInvalidMinCost, "minCost: %s, cost: %s, fee: %s", minIncomeAmt.String(), cost.String(), takerFee.String()) } // Charge taker fee diff --git a/x/iro/keeper/trade_test.go b/x/iro/keeper/trade_test.go index 05befaf8c..7d0b0fd5f 100644 --- a/x/iro/keeper/trade_test.go +++ b/x/iro/keeper/trade_test.go @@ -14,12 +14,6 @@ import ( "github.com/dymensionxyz/dymension/v3/x/iro/types" ) -// FIXME: test trade after settled - -// FIXME: test taker fee (+low values should fail) - -// FIXME: add sell test - func (s *KeeperTestSuite) TestBuy() { rollappId := s.CreateDefaultRollapp() k := s.App.IROKeeper @@ -27,8 +21,8 @@ func (s *KeeperTestSuite) TestBuy() { incentives := types.DefaultIncentivePlanParams() startTime := time.Now() - maxAmt := sdk.NewInt(1_000_000_000) - totalAllocation := sdk.NewInt(1_000_000) + maxAmt := sdk.NewInt(1_000_000_000).MulRaw(1e18) + totalAllocation := sdk.NewInt(1_000_000).MulRaw(1e18) rollapp, _ := s.App.RollappKeeper.GetRollapp(s.Ctx, rollappId) planId, err := k.CreatePlan(s.Ctx, totalAllocation, startTime, startTime.Add(time.Hour), rollapp, curve, incentives) @@ -36,19 +30,26 @@ func (s *KeeperTestSuite) TestBuy() { s.Ctx = s.Ctx.WithBlockTime(startTime.Add(time.Minute)) buyer := sample.Acc() - buyersFunds := sdk.NewCoins(sdk.NewCoin("adym", sdk.NewInt(100_000))) + buyersFunds := sdk.NewCoins(sdk.NewCoin("adym", sdk.NewInt(100_000).MulRaw(1e18))) s.FundAcc(buyer, buyersFunds) + buyAmt := sdk.NewInt(1_000).MulRaw(1e18) + // buy before plan start - should fail - err = k.Buy(s.Ctx.WithBlockTime(startTime.Add(-time.Minute)), planId, buyer, sdk.NewInt(1_000), maxAmt) + err = k.Buy(s.Ctx.WithBlockTime(startTime.Add(-time.Minute)), planId, buyer, buyAmt, maxAmt) s.Require().Error(err) // cost is higher than maxCost specified - should fail - err = k.Buy(s.Ctx, planId, buyer, sdk.NewInt(1_000), sdk.NewInt(10)) + expectedCost := curve.Cost(math.ZeroInt(), buyAmt) + err = k.Buy(s.Ctx, planId, buyer, buyAmt, expectedCost.SubRaw(1)) s.Require().Error(err) // buy more than user's balance - should fail - err = k.Buy(s.Ctx, planId, buyer, sdk.NewInt(900_000), maxAmt) + err = k.Buy(s.Ctx, planId, buyer, sdk.NewInt(100_000).MulRaw(1e18), maxAmt) + s.Require().Error(err) + + // buy very small amount - should fail (as cost ~= 0) + err = k.Buy(s.Ctx, planId, buyer, sdk.NewInt(100), maxAmt) s.Require().Error(err) // assert nothing sold @@ -58,53 +59,47 @@ func (s *KeeperTestSuite) TestBuy() { s.Assert().Equal(buyersFunds.AmountOf("adym"), buyerBalance) // successful buy - amountTokensToBuy := sdk.NewInt(1_000) - expectedCost := curve.Cost(plan.SoldAmt, plan.SoldAmt.Add(amountTokensToBuy)) - err = k.Buy(s.Ctx, planId, buyer, amountTokensToBuy, maxAmt) + err = k.Buy(s.Ctx, planId, buyer, buyAmt, maxAmt) s.Require().NoError(err) plan, _ = k.GetPlan(s.Ctx, planId) - s.Assert().True(plan.SoldAmt.Equal(amountTokensToBuy)) + s.Assert().True(plan.SoldAmt.Equal(buyAmt)) - // buy again, check cost changed - expectedCost2 := curve.Cost(plan.SoldAmt, plan.SoldAmt.Add(amountTokensToBuy)) - err = k.Buy(s.Ctx, planId, buyer, amountTokensToBuy, maxAmt) + // check cost again - should be higher + expectedCost2 := curve.Cost(plan.SoldAmt, plan.SoldAmt.Add(buyAmt)) s.Require().NoError(err) s.Assert().True(expectedCost2.GT(expectedCost)) - // buy more than left - should fail - err = k.Buy(s.Ctx, planId, buyer, sdk.NewInt(999_999), maxAmt) - s.Require().Error(err) - // assert balance balances := s.App.BankKeeper.GetAllBalances(s.Ctx, buyer) takerFee := s.App.BankKeeper.GetAllBalances(s.Ctx, authtypes.NewModuleAddress(txfees.ModuleName)) - expectedBalance := buyersFunds.AmountOf("adym").Sub(expectedCost).Sub(expectedCost2).Sub(takerFee.AmountOf("adym")) + expectedBalance := buyersFunds.AmountOf("adym").Sub(expectedCost).Sub(takerFee.AmountOf("adym")) s.Require().Equal(expectedBalance, balances.AmountOf("adym")) expectedBaseDenom := fmt.Sprintf("%s_%s", types.IROTokenPrefix, rollappId) - s.Require().Equal(amountTokensToBuy.MulRaw(2), balances.AmountOf(expectedBaseDenom)) + s.Require().Equal(buyAmt, balances.AmountOf(expectedBaseDenom)) } func (s *KeeperTestSuite) TestBuyAllocationLimit() { rollappId := s.CreateDefaultRollapp() k := s.App.IROKeeper + // setting "cheap" curve to make calculations easier when buying alot of tokens curve := types.BondingCurve{ - M: math.LegacyMustNewDecFromStr("0.005"), - N: math.LegacyMustNewDecFromStr("0.5"), - C: math.LegacyZeroDec(), + M: math.LegacyMustNewDecFromStr("0"), + N: math.LegacyMustNewDecFromStr("1"), + C: math.LegacyMustNewDecFromStr("0.000001"), } incentives := types.DefaultIncentivePlanParams() startTime := time.Now() - maxAmt := sdk.NewInt(1_000_000_000) - totalAllocation := sdk.NewInt(1_000_000) + maxAmt := sdk.NewInt(1_000_000_000).MulRaw(1e18) + totalAllocation := sdk.NewInt(1_000_000).MulRaw(1e18) rollapp, _ := s.App.RollappKeeper.GetRollapp(s.Ctx, rollappId) planId, err := k.CreatePlan(s.Ctx, totalAllocation, startTime, startTime.Add(time.Hour), rollapp, curve, incentives) s.Require().NoError(err) buyer := sample.Acc() - s.FundAcc(buyer, sdk.NewCoins(sdk.NewCoin("adym", sdk.NewInt(100_000_000_000)))) + s.FundAcc(buyer, sdk.NewCoins(sdk.NewCoin("adym", maxAmt))) // plan start s.Ctx = s.Ctx.WithBlockTime(startTime.Add(time.Minute)) @@ -118,3 +113,125 @@ func (s *KeeperTestSuite) TestBuyAllocationLimit() { err = k.Buy(s.Ctx, planId, buyer, maxSellAmt, maxAmt) s.Require().NoError(err) } + +func (s *KeeperTestSuite) TestTradeAfterSettled() { + rollappId := s.CreateDefaultRollapp() + k := s.App.IROKeeper + curve := types.DefaultBondingCurve() + incentives := types.DefaultIncentivePlanParams() + + startTime := time.Now() + endTime := startTime.Add(time.Hour) + maxAmt := sdk.NewInt(1_000_000_000).MulRaw(1e18) + totalAllocation := sdk.NewInt(1_000_000).MulRaw(1e18) + + rollapp, _ := s.App.RollappKeeper.GetRollapp(s.Ctx, rollappId) + planId, err := k.CreatePlan(s.Ctx, totalAllocation, startTime, endTime, rollapp, curve, incentives) + s.Require().NoError(err) + + buyer := sample.Acc() + buyersFunds := sdk.NewCoins(sdk.NewCoin("adym", sdk.NewInt(100_000).MulRaw(1e18))) + s.FundAcc(buyer, buyersFunds) + + buyAmt := sdk.NewInt(1_000).MulRaw(1e18) + + // Buy before settlement + s.Ctx = s.Ctx.WithBlockTime(startTime.Add(time.Minute)) + err = k.Buy(s.Ctx, planId, buyer, buyAmt, maxAmt) + s.Require().NoError(err) + + // settle + rollappDenom := "dasdasdasdasdsa" + s.FundModuleAcc(types.ModuleName, sdk.NewCoins(sdk.NewCoin(rollappDenom, totalAllocation))) + err = k.Settle(s.Ctx, rollappId, rollappDenom) + s.Require().NoError(err) + + // Attempt to buy after settlement - should fail + err = k.Buy(s.Ctx, planId, buyer, buyAmt, maxAmt) + s.Require().Error(err) +} + +func (s *KeeperTestSuite) TestTakerFee() { + rollappId := s.CreateDefaultRollapp() + k := s.App.IROKeeper + // Bonding curve with fixed price (1 token = 1 adym) + curve := types.BondingCurve{ + M: math.LegacyMustNewDecFromStr("0"), + N: math.LegacyMustNewDecFromStr("1"), + C: math.LegacyMustNewDecFromStr("1"), + } + incentives := types.DefaultIncentivePlanParams() + + startTime := time.Now() + totalAllocation := sdk.NewInt(1_000_000).MulRaw(1e18) + + rollapp, _ := s.App.RollappKeeper.GetRollapp(s.Ctx, rollappId) + planId, err := k.CreatePlan(s.Ctx, totalAllocation, startTime, startTime.Add(time.Hour), rollapp, curve, incentives) + s.Require().NoError(err) + s.Ctx = s.Ctx.WithBlockTime(startTime.Add(time.Minute)) + + buyer := sample.Acc() + buyersFunds := sdk.NewCoins(sdk.NewCoin("adym", sdk.NewInt(100_000).MulRaw(1e18))) + s.FundAcc(buyer, buyersFunds) + + buyAmt := sdk.NewInt(1_000).MulRaw(1e18) + + // Attempt to buy while ignoring taker fee - should fail + err = k.Buy(s.Ctx, planId, buyer, buyAmt, buyAmt) + s.Require().Error(err) + + // Successful buy + expectedTakerFee := s.App.IROKeeper.GetParams(s.Ctx).TakerFee.MulInt(buyAmt).TruncateInt() + err = k.Buy(s.Ctx, planId, buyer, buyAmt, buyAmt.Add(expectedTakerFee)) + s.Require().NoError(err) + + // Check taker fee + takerFee := s.App.BankKeeper.GetAllBalances(s.Ctx, authtypes.NewModuleAddress(txfees.ModuleName)) + s.Require().Equal(expectedTakerFee, takerFee.AmountOf("adym")) +} + +func (s *KeeperTestSuite) TestSell() { + rollappId := s.CreateDefaultRollapp() + k := s.App.IROKeeper + curve := types.DefaultBondingCurve() + incentives := types.DefaultIncentivePlanParams() + + startTime := time.Now() + maxAmt := sdk.NewInt(1_000_000_000).MulRaw(1e18) + totalAllocation := sdk.NewInt(1_000_000).MulRaw(1e18) + + rollapp, _ := s.App.RollappKeeper.GetRollapp(s.Ctx, rollappId) + planId, err := k.CreatePlan(s.Ctx, totalAllocation, startTime, startTime.Add(time.Hour), rollapp, curve, incentives) + s.Require().NoError(err) + s.Ctx = s.Ctx.WithBlockTime(startTime.Add(time.Minute)) + + buyer := sample.Acc() + buyersFunds := sdk.NewCoins(sdk.NewCoin("adym", sdk.NewInt(100_000).MulRaw(1e18))) + s.FundAcc(buyer, buyersFunds) + + buyAmt := sdk.NewInt(1_000).MulRaw(1e18) + + // Buy tokens first + err = k.Buy(s.Ctx, planId, buyer, buyAmt, maxAmt) + s.Require().NoError(err) + + // Sell tokens + sellAmt := sdk.NewInt(500).MulRaw(1e18) + minReceive := sdk.NewInt(1) // Set a very low minReceive for testing purposes + err = k.Sell(s.Ctx, planId, buyer, sellAmt, minReceive) + s.Require().NoError(err) + + // Check balances after sell + balances := s.App.BankKeeper.GetAllBalances(s.Ctx, buyer) + expectedBaseDenom := fmt.Sprintf("%s_%s", types.IROTokenPrefix, rollappId) + s.Require().Equal(buyAmt.Sub(sellAmt), balances.AmountOf(expectedBaseDenom)) + + // Attempt to sell more than owned - should fail + err = k.Sell(s.Ctx, planId, buyer, buyAmt, minReceive) + s.Require().Error(err) + + // Attempt to sell with minReceive higher than possible - should fail + highMinReceive := maxAmt + err = k.Sell(s.Ctx, planId, buyer, sellAmt, highMinReceive) + s.Require().Error(err) +} diff --git a/x/iro/types/bonding_curve.go b/x/iro/types/bonding_curve.go index 7d3012471..f03458273 100644 --- a/x/iro/types/bonding_curve.go +++ b/x/iro/types/bonding_curve.go @@ -7,17 +7,49 @@ import ( ) /* -with the following actions: - - SpotPrice(x) = M*x^N + C - - Cost(x, x1) = integral(x1) - integral(x) - The integral of y = m * x^N + c is (m / (N + 1)) * x^(N + 1) + c * x. +A bonding curve is a mathematical function that defines the relationship between the price and supply of a token. +The general form of a bonding curve is typically expressed as P = M * x^N + C, where: +- P is the price +- X is the supply +- M is a multiplier that affects the curve's steepness +- N is the exponent that determines the curve's shape +- C is a constant that sets the initial price + +The implications of these parameters are significant: +M (multiplier) controls the overall steepness of the curve. A higher M value results in a steeper price increase as supply grows, potentially leading to more rapid value appreciation but also higher volatility. + +N (exponent) shapes the curve's trajectory. When N > 1, the curve becomes convex, accelerating price growth at higher supply levels, which can create strong incentives for early adoption. When 0 < N < 1, the curve is concave, slowing price growth as supply increases, which can promote more stable long-term growth. + +C (constant) sets the starting price when supply is zero, effectively establishing a price floor and influencing the token's initial accessibility. */ const ( - MaxNValue = 10 - MaxPrecision = 2 + MaxNValue = 2 // Maximum allowed value for the N parameter + MaxNPrecision = 3 // Maximum allowed decimal precision for the N parameter ) +/* +The bonding curve implementation based on decimal representation of the X (rollapp's tokens) and Y (DYM) values. +we use scaling functions to convert between the decimal scale and the base denomination. +*/ + +// Scales x from it's base denomination to a decimal representation +// This is used to scale X before passing it to the bonding curve functions +func ScaleXFromBase(x math.Int, precision int64) math.LegacyDec { + return math.LegacyNewDecFromIntWithPrec(x, precision) +} + +// Scales y from the decimal scale to it's base denomination +func ScaleDYMToBase(y math.LegacyDec) math.Int { + return y.MulInt(math.NewInt(1e18)).TruncateInt() +} + +func (lbc BondingCurve) SupplyDecimals() int64 { + // TODO: allow to be set on creation instead of using default + rollappTokenDefaultDecimals := int64(18) + return rollappTokenDefaultDecimals +} + func NewBondingCurve(m, n, c math.LegacyDec) BondingCurve { return BondingCurve{ M: m, @@ -51,9 +83,8 @@ func (lbc BondingCurve) ValidateBasic() error { return errorsmod.Wrapf(ErrInvalidBondingCurve, "c: %s", lbc.C.String()) } - // Check precision for M, N, and C - if !checkPrecision(lbc.M) || !checkPrecision(lbc.N) || !checkPrecision(lbc.C) { - return errorsmod.Wrapf(ErrInvalidBondingCurve, "m, n, and c must have at most %d decimal places", MaxPrecision) + if !checkPrecision(lbc.N) { + return errorsmod.Wrapf(ErrInvalidBondingCurve, "N must have at most %d decimal places", MaxNPrecision) } return nil @@ -62,41 +93,92 @@ func (lbc BondingCurve) ValidateBasic() error { // checkPrecision checks if a math.LegacyDec has at most MaxPrecision decimal places func checkPrecision(d math.LegacyDec) bool { // Multiply by 10^MaxPrecision and check if it's an integer - multiplied := d.Mul(math.LegacyNewDec(10).Power(uint64(MaxPrecision))) + multiplied := d.Mul(math.LegacyNewDec(10).Power(uint64(MaxNPrecision))) return multiplied.IsInteger() } // SpotPrice returns the spot price at x func (lbc BondingCurve) SpotPrice(x math.Int) math.LegacyDec { // we use osmomath as it support Power function - xDec := osmomath.BigDecFromSDKDec(x.ToLegacyDec()) + xDec := osmomath.BigDecFromSDKDec(ScaleXFromBase(x, lbc.SupplyDecimals())) nDec := osmomath.BigDecFromSDKDec(lbc.N) mDec := osmomath.BigDecFromSDKDec(lbc.M) - xPowN := xDec.Power(nDec) // Calculate x^N - return mDec.Mul(xPowN).SDKDec().Add(lbc.C) // M * x^N + C + var xPowN osmomath.BigDec + if xDec.LT(osmomath.OneDec()) { + xPowN = osmomath.ZeroDec() + } else { + xPowN = xDec.Power(nDec) // Calculate x^N + } + price := mDec.Mul(xPowN).SDKDec().Add(lbc.C) // M * x^N + C + return price } -// Cost returns the cost of buying x1 - x tokens +/* +The cost to purchase tokens from supply S1 to S2 is given by the definite integral of this function from S1 to S2. Mathematically, this is expressed as: +Cost = ∫(S1 to S2) (M * S^N + C) dS +Solving this integral yields: +Cost = [M / (N + 1) * S^(N + 1) + C * S](S1 to S2) +*/ func (lbc BondingCurve) Cost(x, x1 math.Int) math.Int { return lbc.Integral(x1).Sub(lbc.Integral(x)) } // The Integral of y = M * x^N + C is: // -// (M / (N + 1)) * x^(N + 1) + C * x. +// Cost = (M / (N + 1)) * x^(N + 1) + C * x. func (lbc BondingCurve) Integral(x math.Int) math.Int { // we use osmomath as it support Power function - xDec := osmomath.BigDecFromSDKDec(x.ToLegacyDec()) + xDec := osmomath.BigDecFromSDKDec(ScaleXFromBase(x, lbc.SupplyDecimals())) mDec := osmomath.BigDecFromSDKDec(lbc.M) cDec := osmomath.BigDecFromSDKDec(lbc.C) nPlusOne := osmomath.BigDecFromSDKDec(lbc.N.Add(math.LegacyNewDec(1))) - xPowNplusOne := xDec.Power(nPlusOne) // Calculate x^(N + 1) + var xPowNplusOne osmomath.BigDec + if xDec.LT(osmomath.OneDec()) { + xPowNplusOne = osmomath.ZeroDec() + } else { + xPowNplusOne = xDec.Power(nPlusOne) // Calculate x^(N + 1) + } mDivNPlusOne := mDec.QuoMut(nPlusOne) // Calculate m / (N + 1) cx := cDec.Mul(xDec) // Calculate C * x // Calculate the integral integral := xPowNplusOne.Mul(mDivNPlusOne).Add(cx) - return integral.SDKDec().TruncateInt() + return ScaleDYMToBase(integral.SDKDec()) +} + +// CalculateM computes the M parameter for a bonding curve +// It's actually not used in the codebase, but it's here for reference and for testing purposes +// val: total value to be raised (in DYM, not adym) +// t: total number of tokens (rollapp's tokens in decimal representation, not base denomination) +// n: curve exponent +// c: constant term +// M = (VAL - C * T) * (N + 1) / T^(N+1) +func CalculateM(val, t, n, c math.LegacyDec) math.LegacyDec { + valBig := osmomath.BigDecFromSDKDec(val) + tBig := osmomath.BigDecFromSDKDec(t) + nBig := osmomath.BigDecFromSDKDec(n) + cBig := osmomath.BigDecFromSDKDec(c) + + // Calculate N + 1 + nPlusOne := nBig.Add(osmomath.OneDec()) + + // Calculate T^(N+1) + tPowNPlusOne := tBig.Power(nPlusOne) + + // Calculate C * T + cTimesT := cBig.Mul(tBig) + + // Calculate VAL - C * Z + numerator := valBig.Sub(cTimesT) + + // Calculate (VAL - C * Z) * (N + 1) + numerator = numerator.Mul(nPlusOne) + + // Calculate M = numerator / Z^(N+1) + m := numerator.Quo(tPowNPlusOne) + + // Convert back to math.LegacyDec and return + return m.SDKDec() } diff --git a/x/iro/types/bonding_curve_test.go b/x/iro/types/bonding_curve_test.go index 73d8be2b8..b4a7b081e 100644 --- a/x/iro/types/bonding_curve_test.go +++ b/x/iro/types/bonding_curve_test.go @@ -10,8 +10,20 @@ import ( "github.com/dymensionxyz/dymension/v3/x/iro/types" ) -// y=mx^n+c -// m >= 0, c > 0 +// approxEqualInt checks if two math.Ints are approximately equal +func approxEqualInt(t *testing.T, expected, actual math.Int) { + defaultTolerance := math.NewInt(1).MulRaw(1e9) // one millionth of a dym + diff := expected.Sub(actual).Abs() + require.True(t, diff.LTE(defaultTolerance), fmt.Sprintf("expected %s, got %s, diff %s", expected, actual, diff)) +} + +// approxEqualDec checks if two math.Decs are approximately equal +func approxEqualDec(t *testing.T, expected, actual math.LegacyDec) { + defaultTolerance := math.LegacyNewDecWithPrec(1, 9) // one millionth of a dym + diff := expected.Sub(actual).Abs() + require.True(t, diff.LTE(defaultTolerance), fmt.Sprintf("expected %s, got %s, diff %s", expected, actual, diff)) +} + func TestBondingCurve_ValidateBasic(t *testing.T) { tests := []struct { name string @@ -20,16 +32,15 @@ func TestBondingCurve_ValidateBasic(t *testing.T) { c float64 expectErr bool }{ - {"Valid bonding curve", 2, 2.23, 3, false}, - {"Valid linear curve", 0.2, 0.88, 3.22, false}, - {"Valid const price curve", 0, 1, 3, false}, + {"Valid bonding curve", 1, 1, 0, false}, + {"Valid linear curve", 0.000002, 1, 0.00022, false}, + {"Valid power curve N>1", 0.1234, 1.23, 0.002, false}, + {"Valid power curve N<1", 0.1234, 0.76, 0.002, false}, {"Invalid C value", 2, 1, -1, true}, {"Invalid M value", -2, 1, 3, true}, {"Invalid N value", 2, -1, 3, true}, {"Too high N value", 2, 11, 3, true}, - {"Precision check M", 2.222, 1, 3, true}, {"Precision check N", 2, 1.2421, 3, true}, - {"Precision check C", 2, 1, 3.321312, true}, } for _, tt := range tests { @@ -58,186 +69,165 @@ func TestBondingCurve_Linear(t *testing.T) { curve := types.NewBondingCurve(m, n, c) // Test values - x1 := math.NewInt(0) - x2 := math.NewInt(10) - x3 := math.NewInt(100) + x1 := math.NewInt(0).MulRaw(1e18) + x2 := math.NewInt(10).MulRaw(1e18) + x3 := math.NewInt(100).MulRaw(1e18) // Expected results - spotPrice1 := math.NewInt(0) // 1*0^1 + 0 - spotPrice2 := math.NewInt(10) // 1*10^1 + 0 - spotPrice3 := math.NewInt(100) // 1*100^1 + 0 + spotPrice1 := math.LegacyNewDec(0) // 1*0^1 + 0 + spotPrice2 := math.LegacyNewDec(10) // 1*10^1 + 0 + spotPrice3 := math.LegacyNewDec(100) // 1*100^1 + 0 // y = 1/2*x^2 - integral2 := math.NewInt(50) // (1/2)*10^2 - integral3 := math.NewInt(5000) // (1/2)*100^2 + integral2 := math.NewInt(50).MulRaw(1e18) // (1/2)*10^2 + integral3 := math.NewInt(5000).MulRaw(1e18) // (1/2)*100^2 - cost1to2 := math.NewInt(50) // 50 - 0 - cost2to3 := math.NewInt(4950) // 5000 - 50 + cost1to2 := integral2 // 50 - 0 + cost2to3 := math.NewInt(4950).MulRaw(1e18) // 5000 - 50 - require.Equal(t, math.ZeroInt(), curve.Integral(x1)) - require.Equal(t, integral2, curve.Integral(x2)) - require.Equal(t, integral3, curve.Integral(x3)) + approxEqualInt(t, math.ZeroInt(), curve.Integral(x1)) + approxEqualInt(t, integral2, curve.Integral(x2)) + approxEqualInt(t, integral3, curve.Integral(x3)) - require.Equal(t, spotPrice1, curve.SpotPrice(x1).TruncateInt()) - require.Equal(t, spotPrice2, curve.SpotPrice(x2).TruncateInt()) - require.Equal(t, spotPrice3, curve.SpotPrice(x3).TruncateInt()) + approxEqualDec(t, spotPrice1, curve.SpotPrice(x1)) + approxEqualDec(t, spotPrice2, curve.SpotPrice(x2)) + approxEqualDec(t, spotPrice3, curve.SpotPrice(x3)) - require.Equal(t, cost1to2, curve.Cost(x1, x2)) - require.Equal(t, cost2to3, curve.Cost(x2, x3)) + approxEqualInt(t, cost1to2, curve.Cost(x1, x2)) + approxEqualInt(t, cost2to3, curve.Cost(x2, x3)) } // Scenario 2: Quadratic Curve with Offset func TestBondingCurve_Quadratic(t *testing.T) { // y=2x^2+10 // integral of y = 2/3*x^3 + 10*x - // m := math.NewInt(2) m := math.LegacyMustNewDecFromStr("2") n := math.LegacyMustNewDecFromStr("2") c := math.LegacyMustNewDecFromStr("10") curve := types.NewBondingCurve(m, n, c) // Test values - x1 := math.NewInt(0) - x2 := math.NewInt(5) - x3 := math.NewInt(10) + x1 := math.NewInt(0).MulRaw(1e18) + x2 := math.NewInt(5).MulRaw(1e18) + x3 := math.NewInt(10).MulRaw(1e18) // Expected results - spotPrice1 := math.NewInt(10) // 2*0^2 + 10 - spotPrice2 := math.NewInt(60) // 2*5^2 + 10 - spotPrice3 := math.NewInt(210) // 2*10^2 + 10 + spotPrice1 := math.LegacyNewDec(10) // 2*0^2 + 10 + spotPrice2 := math.LegacyNewDec(60) // 2*5^2 + 10 + spotPrice3 := math.LegacyNewDec(210) // 2*10^2 + 10 - integral1 := math.NewInt(0) // (2/3)*0^3 + 10*0 - integral2 := math.NewInt(133) // (2/3)*5^3 + 10*5 - integral3 := math.NewInt(766) // (2/3)*10^3 + 10*10 + integral1 := math.NewInt(0).MulRaw(1e18) // (2/3)*0^3 + 10*0 + integral2 := math.LegacyMustNewDecFromStr("133.3333333333").MulInt64(1e18).TruncateInt() // (2/3)*5^3 + 10*5 // (2/3)*10^3 + 10*10 + integral3 := math.LegacyMustNewDecFromStr("766.6666666666").MulInt64(1e18).TruncateInt() // (2/3)*10^3 + 10*10 - cost1to2 := math.NewInt(133) // (2/3)*5^3 + 10*5 - (2/3)*0^3 - 10*0 - cost2to3 := math.NewInt(633) // (2/3)*10^3 + 10*10 - (2/3)*5^3 - 10*5 + cost1to2 := integral2 // (2/3)*5^3 + 10*5 - (2/3)*0^3 - 10*0 + cost2to3 := math.LegacyMustNewDecFromStr("633.3333333333").MulInt64(1e18).TruncateInt() // (2/3)*10^3 + 10*10 - (2/3)*5^3 - 10*5 - require.Equal(t, integral1, curve.Integral(x1)) - require.Equal(t, integral2, curve.Integral(x2)) - require.Equal(t, integral3, curve.Integral(x3)) + approxEqualInt(t, integral1, curve.Integral(x1)) + approxEqualInt(t, integral2, curve.Integral(x2)) + approxEqualInt(t, integral3, curve.Integral(x3)) - require.Equal(t, spotPrice1, curve.SpotPrice(x1).TruncateInt()) - require.Equal(t, spotPrice2, curve.SpotPrice(x2).TruncateInt()) - require.Equal(t, spotPrice3, curve.SpotPrice(x3).TruncateInt()) + approxEqualDec(t, spotPrice1, curve.SpotPrice(x1)) + approxEqualDec(t, spotPrice2, curve.SpotPrice(x2)) + approxEqualDec(t, spotPrice3, curve.SpotPrice(x3)) - require.Equal(t, cost1to2, curve.Cost(x1, x2)) - require.Equal(t, cost2to3, curve.Cost(x2, x3)) + approxEqualInt(t, cost1to2, curve.Cost(x1, x2)) + approxEqualInt(t, cost2to3, curve.Cost(x2, x3)) } -// Scenario 3: Cubic Curve with Large Numbers -func TestBondingCurve_Cubic(t *testing.T) { - // y=3x^3+1000 - // integral of y = 3/4*x^4 + 1000*x - m := math.LegacyMustNewDecFromStr("3") - n := math.LegacyMustNewDecFromStr("3") - c := math.LegacyMustNewDecFromStr("1000") +// Scenario: Square Root Curve +func TestBondingCurve_SquareRoot(t *testing.T) { + // y = m*x^0.5 + c + // integral of y = (2/3)*m*x^1.5 + c*x + m := math.LegacyMustNewDecFromStr("2.24345436") + n := math.LegacyMustNewDecFromStr("0.5") + c := math.LegacyMustNewDecFromStr("10.5443534") curve := types.NewBondingCurve(m, n, c) // Test values - x1 := math.NewInt(0) - x2 := math.NewInt(100) - x3 := math.NewInt(1000) + x1 := math.NewInt(0).MulRaw(1e18) + x2 := math.NewInt(100).MulRaw(1e18) + x3 := math.NewInt(10000).MulRaw(1e18) - // Expected results - spotPrice1 := math.NewInt(1000) // 3*0^3 + 1000 - spotPrice2 := math.NewInt(3001000) // 3*100^3 + 1000 - spotPrice3 := math.NewInt(3000001000) // 3*1000^3 + 1000 + // Expected results (rounded to nearest integer) + spotPrice1 := math.LegacyMustNewDecFromStr("10.5443534") // 2.24345436*0^0.5 + 10.5443534 ≈ 11 + spotPrice2 := math.LegacyMustNewDecFromStr("32.978897") // 2.24345436*100^0.5 + 10.5443534 ≈ 33 + spotPrice3 := math.LegacyMustNewDecFromStr("234.8897894") // 2.24345436*10000^0.5 + 10.5443534 ≈ 235 - integral1 := math.NewInt(0) // (3/4)*0^4 + 1000*0 - integral2 := math.NewInt(75100000) // (3/4)*100^4 + 1000*100 - integral3 := math.NewInt(750001000000) // (3/4)*1000^4 + 1000*1000 + integral1 := math.LegacyMustNewDecFromStr("0").MulInt64(1e18).TruncateInt() // (2/3)*2.24345436*0^1.5 + 10.5443534*0 = 0 + integral2 := math.LegacyMustNewDecFromStr("2550.07158").MulInt64(1e18).TruncateInt() // (2/3)*2.24345436*100^1.5 + 10.5443534*100 ≈ 2550 + integral3 := math.LegacyMustNewDecFromStr("1601079.774").MulInt64(1e18).TruncateInt() // (2/3)*2.24345436*10000^1.5 + 10.5443534*10000 ≈ 1598850 - cost1to2 := math.NewInt(75100000) // (3/4)*100^4 + 1000*100 - (3/4)*0^4 - 1000*0 - cost2to3 := math.NewInt(749925900000) // (3/4)*1000^4 + 1000*1000 - (3/4)*100^4 - 1000*100 + cost1to2 := integral2 // integral2 - integral1 + cost2to3 := math.LegacyMustNewDecFromStr("1598529.70242").MulInt64(1e18).TruncateInt() // integral3 - integral2 - require.Equal(t, integral1, curve.Integral(x1)) - require.Equal(t, integral2, curve.Integral(x2)) - require.Equal(t, integral3, curve.Integral(x3)) + approxEqualInt(t, integral1, curve.Integral(x1)) + approxEqualInt(t, integral2, curve.Integral(x2)) + approxEqualInt(t, integral3, curve.Integral(x3)) - require.Equal(t, spotPrice1, curve.SpotPrice(x1).TruncateInt()) - require.Equal(t, spotPrice2, curve.SpotPrice(x2).TruncateInt()) - require.Equal(t, spotPrice3, curve.SpotPrice(x3).TruncateInt()) + approxEqualDec(t, spotPrice1, curve.SpotPrice(x1)) + approxEqualDec(t, spotPrice2, curve.SpotPrice(x2)) + approxEqualDec(t, spotPrice3, curve.SpotPrice(x3)) - require.Equal(t, cost1to2, curve.Cost(x1, x2)) - require.Equal(t, cost2to3, curve.Cost(x2, x3)) + approxEqualInt(t, cost1to2, curve.Cost(x1, x2)) + approxEqualInt(t, cost2to3, curve.Cost(x2, x3)) } -// Scenario 4: High Exponent Curve -func TestBondingCurve_HighExponent(t *testing.T) { - // y=x^5+100 - // integral of y = 1/6*x^6 + 100*x - - m := math.LegacyMustNewDecFromStr("1") - n := math.LegacyMustNewDecFromStr("5") - c := math.LegacyMustNewDecFromStr("100") - curve := types.NewBondingCurve(m, n, c) - - // Test values - x1 := math.NewInt(0) - x2 := math.NewInt(2) - x3 := math.NewInt(10) - - // Expected results - spotPrice1 := math.NewInt(100) // 1*0^5 + 100 - spotPrice2 := math.NewInt(132) // 1*2^5 + 100 - spotPrice3 := math.NewInt(100100) // 1*10^5 + 100 - - integral1 := math.NewInt(0) // (1/6)*0^6 + 100*0 - integral2 := math.NewInt(210) // (1/6)*2^6 + 100*2 - integral3 := math.NewInt(167666) // (1/6)*10^6 + 100*10 - - cost1to2 := math.NewInt(210) // 210 - 0 - cost2to3 := math.NewInt(167456) // 167666 - 210 - - require.Equal(t, spotPrice1, curve.SpotPrice(x1).TruncateInt()) - require.Equal(t, spotPrice2, curve.SpotPrice(x2).TruncateInt()) - require.Equal(t, spotPrice3, curve.SpotPrice(x3).TruncateInt()) +// test very small x returns 0 +func TestBondingCurve_SmallX(t *testing.T) { + curve := types.DefaultBondingCurve() - require.Equal(t, integral1, curve.Integral(x1)) - require.Equal(t, integral2, curve.Integral(x2)) - require.Equal(t, integral3, curve.Integral(x3)) + // less than 1 token is not enough + require.True(t, curve.SpotPrice(math.NewInt(1_000_000)).IsZero()) + require.True(t, curve.Integral(math.NewInt(1_000_000)).IsZero()) + require.True(t, curve.Integral(math.NewInt(1).MulRaw(1e17)).IsZero()) - require.Equal(t, cost1to2, curve.Cost(x1, x2)) - require.Equal(t, cost2to3, curve.Cost(x2, x3)) + // even 1 token is enough + require.False(t, curve.Integral(math.NewInt(1).MulRaw(1e18)).IsZero()) + require.False(t, curve.SpotPrice(math.NewInt(1).MulRaw(1e18)).IsZero()) } -// Scenario: Square Root Curve -// FIXME: allow approx equal for test to pass -func TestBondingCurve_SquareRoot(t *testing.T) { - t.Skip("TODO: add approx equal for test to pass") - // y = m*x^0.5 + c - // integral of y = (3/4)*m*x^1.5 + c*x - m := math.LegacyMustNewDecFromStr("2.24345436") - n := math.LegacyMustNewDecFromStr("0.5") - c := math.LegacyMustNewDecFromStr("10.5443534") - curve := types.NewBondingCurve(m, n, c) - - // Test values - x1 := math.NewInt(0) - x2 := math.NewInt(100) - x3 := math.NewInt(10000) - - // Expected results (rounded to nearest integer) - spotPrice1 := math.NewInt(11) // 2.24345436*0^0.5 + 10.5443534 ≈ 11 - spotPrice2 := math.NewInt(33) // 2.24345436*100^0.5 + 10.5443534 ≈ 33 - spotPrice3 := math.NewInt(235) // 2.24345436*10000^0.5 + 10.5443534 ≈ 235 +/* +Real world scenario: +- A project wants to raise 100_000 DYM for 1_000_000 RA tokens +- N = 1 +- C = 0.001 (1% of the average price) - integral1 := math.NewInt(0) // (2/3)*2.24345436*0^1.5 + 10.5443534*0 = 0 - integral2 := math.NewInt(2550) // (2/3)*2.24345436*100^1.5 + 10.5443534*100 ≈ 2550 - integral3 := math.NewInt(1598850) // (2/3)*2.24345436*10000^1.5 + 10.5443534*10000 ≈ 1598850 +Expected M value: 0.000000198 +*/ +func TestUseCaseA(t *testing.T) { + // Test case parameters + val := math.LegacyNewDecFromInt(math.NewInt(100_000)) // 100,000 DYM to raise + z := math.LegacyNewDecFromInt(math.NewInt(1_000_000)) // 1,000,000 RA tokens + n := math.LegacyNewDec(1) // N = 1 (linear curve) + c := math.LegacyNewDecWithPrec(1, 3) // C = 0.001 (1% of the average price) - cost1to2 := math.NewInt(2550) // integral2 - integral1 - cost2to3 := math.NewInt(1596300) // integral3 - integral2 + // Expected M calculation: + expectedM := math.LegacyMustNewDecFromStr("0.000000198") - require.Equal(t, integral1, curve.Integral(x1)) - require.Equal(t, integral2, curve.Integral(x2)) - require.Equal(t, integral3, curve.Integral(x3)) + // Calculate M + m := types.CalculateM(val, z, n, c) + require.Equal(t, expectedM, m) - require.Equal(t, spotPrice1, curve.SpotPrice(x1).TruncateInt()) - require.Equal(t, spotPrice2, curve.SpotPrice(x2).TruncateInt()) - require.Equal(t, spotPrice3, curve.SpotPrice(x3).TruncateInt()) + curve := types.NewBondingCurve(m, n, c) - require.Equal(t, cost1to2, curve.Cost(x1, x2)) - require.Equal(t, cost2to3, curve.Cost(x2, x3)) + // Verify that the integral of the curve at Z equals VAL + integral := curve.Integral(z.MulInt64(1e18).TruncateInt()) + approxEqualInt(t, val.MulInt64(1e18).TruncateInt(), integral) + + // verify that the cost early is lower than the cost later + // test for buying 1000 RA tokens + costA := curve.Cost(math.ZeroInt(), math.NewInt(1000).MulRaw(1e18)) + costB := curve.Cost(math.NewInt(900_000).MulRaw(1e18), math.NewInt(901_000).MulRaw(1e18)) + t.Log(costA, costB) + + // Calculate the actual difference + costDifference := costB.Sub(costA) + + // Define a threshold for the cost difference (e.g., 5% of costA) + threshold := costA.MulRaw(5).QuoRaw(100) + // Assert that the cost difference is greater than the threshold + require.True(t, costDifference.GT(threshold), + "Cost difference (%s) should be greater than threshold (%s)", + costDifference, threshold) } diff --git a/x/iro/types/genesis_test.go b/x/iro/types/genesis_test.go index 54aa51f69..ddef613aa 100644 --- a/x/iro/types/genesis_test.go +++ b/x/iro/types/genesis_test.go @@ -19,8 +19,7 @@ func TestGenesisState_Validate(t *testing.T) { genState: types.DefaultGenesis(), valid: true, }, - // TODO: add more test cases (test params validation, test plan validation) - // TODO: test duplicates, + // TODO: add more test cases (test params validation, test plan validation), test duplicates, } for _, tc := range tests { t.Run(tc.desc, func(t *testing.T) { diff --git a/x/iro/types/msgs.go b/x/iro/types/msgs.go index 25a351119..46e0ae0c6 100644 --- a/x/iro/types/msgs.go +++ b/x/iro/types/msgs.go @@ -15,20 +15,25 @@ var ( _ sdk.Msg = &MsgUpdateParams{} ) +// ValidateBasic performs basic validation checks on the MsgCreatePlan message. +// It ensures that the owner address is valid, the bonding curve is valid, the allocated amount +// is greater than the minimum token allocation, the pre-launch time is before the start time, +// and the incentive plan parameters are valid. func (m *MsgCreatePlan) ValidateBasic() error { _, err := sdk.AccAddressFromBech32(m.Owner) if err != nil { return sdkerrors.ErrInvalidAddress.Wrapf("invalid owner address: %s", err) } - if !m.AllocatedAmount.IsPositive() { - return ErrInvalidAllocation - } - if err := m.BondingCurve.ValidateBasic(); err != nil { return errors.Join(ErrInvalidBondingCurve, err) } + allocationDec := ScaleXFromBase(m.AllocatedAmount, m.BondingCurve.SupplyDecimals()) + if !allocationDec.GT(MinTokenAllocation) { + return ErrInvalidAllocation + } + if m.PreLaunchTime.Before(m.StartTime) { return ErrInvalidEndTime } @@ -57,8 +62,8 @@ func (m *MsgBuy) ValidateBasic() error { return sdkerrors.ErrInvalidRequest.Wrapf("amount %v must be positive", m.Amount) } - if m.ExpectedOutAmount.IsNil() || !m.ExpectedOutAmount.IsPositive() { - return sdkerrors.ErrInvalidRequest.Wrapf("expected out amount %v must be positive", m.ExpectedOutAmount) + if m.MaxCostAmount.IsNil() || !m.MaxCostAmount.IsPositive() { + return sdkerrors.ErrInvalidRequest.Wrapf("expected out amount %v must be positive", m.MaxCostAmount) } return nil @@ -81,8 +86,8 @@ func (m *MsgSell) ValidateBasic() error { return sdkerrors.ErrInvalidRequest.Wrapf("amount %v must be positive", m.Amount) } - if m.ExpectedOutAmount.IsNil() || !m.ExpectedOutAmount.IsPositive() { - return sdkerrors.ErrInvalidRequest.Wrapf("expected out amount %v must be positive", m.ExpectedOutAmount) + if m.MinIncomeAmount.IsNil() || !m.MinIncomeAmount.IsPositive() { + return sdkerrors.ErrInvalidRequest.Wrapf("expected out amount %v must be positive", m.MinIncomeAmount) } return nil diff --git a/x/iro/types/params.go b/x/iro/types/params.go index fc4541bc7..a35b6e666 100644 --- a/x/iro/types/params.go +++ b/x/iro/types/params.go @@ -50,7 +50,7 @@ func (p Params) Validate() error { } if p.MinPlanDuration < 0 { - return fmt.Errorf("minimum plan duration must be non-negative: %s", p.MinPlanDuration) + return fmt.Errorf("minimum plan duration must be non-negative: %v", p.MinPlanDuration) } if p.IncentivesMinNumEpochsPaidOver < 1 { diff --git a/x/iro/types/plan.go b/x/iro/types/plan.go index ca6c805bf..189fb5c90 100644 --- a/x/iro/types/plan.go +++ b/x/iro/types/plan.go @@ -12,6 +12,8 @@ import ( const IROTokenPrefix = "future" +var MinTokenAllocation = math.LegacyNewDec(10) // min allocation in decimal representation + func NewPlan(id uint64, rollappId string, allocation sdk.Coin, curve BondingCurve, start time.Time, end time.Time, incentivesParams IncentivePlanParams) Plan { plan := Plan{ Id: id, @@ -30,12 +32,14 @@ func NewPlan(id uint64, rollappId string, allocation sdk.Coin, curve BondingCurv // ValidateBasic checks if the plan is valid func (p Plan) ValidateBasic() error { - if !p.TotalAllocation.IsPositive() { - return ErrInvalidAllocation - } if err := p.BondingCurve.ValidateBasic(); err != nil { return errors.Join(ErrInvalidBondingCurve, err) } + // check that the allocation is greater than the minimal allowed token allocation + allocationDec := ScaleXFromBase(p.TotalAllocation.Amount, p.BondingCurve.SupplyDecimals()) + if !allocationDec.GT(MinTokenAllocation) { + return ErrInvalidAllocation + } if p.PreLaunchTime.Before(p.StartTime) { return ErrInvalidEndTime } @@ -56,6 +60,11 @@ func (p Plan) ValidateBasic() error { return nil } +// SpotPrice returns the spot price of the plan +func (p Plan) SpotPrice() math.LegacyDec { + return p.BondingCurve.SpotPrice(p.SoldAmt) +} + func (p Plan) IsSettled() bool { return p.SettledDenom != "" } diff --git a/x/iro/types/query.pb.go b/x/iro/types/query.pb.go index a0d9e2bb0..2b6332638 100644 --- a/x/iro/types/query.pb.go +++ b/x/iro/types/query.pb.go @@ -379,23 +379,23 @@ func (m *QueryPlanByRollappResponse) GetPlan() *Plan { return nil } -// QueryPriceRequest is the request type for the Query/QueryPrice RPC method. -type QueryPriceRequest struct { +// QuerySpotPriceRequest is the request type for the Query/QuerySpotPrice RPC method. +type QuerySpotPriceRequest struct { PlanId string `protobuf:"bytes,1,opt,name=plan_id,json=planId,proto3" json:"plan_id,omitempty"` } -func (m *QueryPriceRequest) Reset() { *m = QueryPriceRequest{} } -func (m *QueryPriceRequest) String() string { return proto.CompactTextString(m) } -func (*QueryPriceRequest) ProtoMessage() {} -func (*QueryPriceRequest) Descriptor() ([]byte, []int) { +func (m *QuerySpotPriceRequest) Reset() { *m = QuerySpotPriceRequest{} } +func (m *QuerySpotPriceRequest) String() string { return proto.CompactTextString(m) } +func (*QuerySpotPriceRequest) ProtoMessage() {} +func (*QuerySpotPriceRequest) Descriptor() ([]byte, []int) { return fileDescriptor_ae2c72bd0c23c1c0, []int{8} } -func (m *QueryPriceRequest) XXX_Unmarshal(b []byte) error { +func (m *QuerySpotPriceRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *QueryPriceRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *QuerySpotPriceRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_QueryPriceRequest.Marshal(b, m, deterministic) + return xxx_messageInfo_QuerySpotPriceRequest.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -405,42 +405,42 @@ func (m *QueryPriceRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, e return b[:n], nil } } -func (m *QueryPriceRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryPriceRequest.Merge(m, src) +func (m *QuerySpotPriceRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QuerySpotPriceRequest.Merge(m, src) } -func (m *QueryPriceRequest) XXX_Size() int { +func (m *QuerySpotPriceRequest) XXX_Size() int { return m.Size() } -func (m *QueryPriceRequest) XXX_DiscardUnknown() { - xxx_messageInfo_QueryPriceRequest.DiscardUnknown(m) +func (m *QuerySpotPriceRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QuerySpotPriceRequest.DiscardUnknown(m) } -var xxx_messageInfo_QueryPriceRequest proto.InternalMessageInfo +var xxx_messageInfo_QuerySpotPriceRequest proto.InternalMessageInfo -func (m *QueryPriceRequest) GetPlanId() string { +func (m *QuerySpotPriceRequest) GetPlanId() string { if m != nil { return m.PlanId } return "" } -// QueryPriceResponse is the response type for the Query/QueryPrice RPC method. -type QueryPriceResponse struct { - Price *types.Coin `protobuf:"bytes,1,opt,name=price,proto3" json:"price,omitempty"` +// QuerySpotPriceResponse is the response type for the Query/QuerySpotPrice RPC method. +type QuerySpotPriceResponse struct { + Price github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,1,opt,name=price,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"price"` } -func (m *QueryPriceResponse) Reset() { *m = QueryPriceResponse{} } -func (m *QueryPriceResponse) String() string { return proto.CompactTextString(m) } -func (*QueryPriceResponse) ProtoMessage() {} -func (*QueryPriceResponse) Descriptor() ([]byte, []int) { +func (m *QuerySpotPriceResponse) Reset() { *m = QuerySpotPriceResponse{} } +func (m *QuerySpotPriceResponse) String() string { return proto.CompactTextString(m) } +func (*QuerySpotPriceResponse) ProtoMessage() {} +func (*QuerySpotPriceResponse) Descriptor() ([]byte, []int) { return fileDescriptor_ae2c72bd0c23c1c0, []int{9} } -func (m *QueryPriceResponse) XXX_Unmarshal(b []byte) error { +func (m *QuerySpotPriceResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *QueryPriceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *QuerySpotPriceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_QueryPriceResponse.Marshal(b, m, deterministic) + return xxx_messageInfo_QuerySpotPriceResponse.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -450,24 +450,17 @@ func (m *QueryPriceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, return b[:n], nil } } -func (m *QueryPriceResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryPriceResponse.Merge(m, src) +func (m *QuerySpotPriceResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QuerySpotPriceResponse.Merge(m, src) } -func (m *QueryPriceResponse) XXX_Size() int { +func (m *QuerySpotPriceResponse) XXX_Size() int { return m.Size() } -func (m *QueryPriceResponse) XXX_DiscardUnknown() { - xxx_messageInfo_QueryPriceResponse.DiscardUnknown(m) +func (m *QuerySpotPriceResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QuerySpotPriceResponse.DiscardUnknown(m) } -var xxx_messageInfo_QueryPriceResponse proto.InternalMessageInfo - -func (m *QueryPriceResponse) GetPrice() *types.Coin { - if m != nil { - return m.Price - } - return nil -} +var xxx_messageInfo_QuerySpotPriceResponse proto.InternalMessageInfo // QueryCostRequest is the request type for the Query/QueryCost RPC method. type QueryCostRequest struct { @@ -662,8 +655,8 @@ func init() { proto.RegisterType((*QueryPlanResponse)(nil), "dymensionxyz.dymension.iro.QueryPlanResponse") proto.RegisterType((*QueryPlanByRollappRequest)(nil), "dymensionxyz.dymension.iro.QueryPlanByRollappRequest") proto.RegisterType((*QueryPlanByRollappResponse)(nil), "dymensionxyz.dymension.iro.QueryPlanByRollappResponse") - proto.RegisterType((*QueryPriceRequest)(nil), "dymensionxyz.dymension.iro.QueryPriceRequest") - proto.RegisterType((*QueryPriceResponse)(nil), "dymensionxyz.dymension.iro.QueryPriceResponse") + proto.RegisterType((*QuerySpotPriceRequest)(nil), "dymensionxyz.dymension.iro.QuerySpotPriceRequest") + proto.RegisterType((*QuerySpotPriceResponse)(nil), "dymensionxyz.dymension.iro.QuerySpotPriceResponse") proto.RegisterType((*QueryCostRequest)(nil), "dymensionxyz.dymension.iro.QueryCostRequest") proto.RegisterType((*QueryCostResponse)(nil), "dymensionxyz.dymension.iro.QueryCostResponse") proto.RegisterType((*QueryClaimedRequest)(nil), "dymensionxyz.dymension.iro.QueryClaimedRequest") @@ -675,56 +668,57 @@ func init() { } var fileDescriptor_ae2c72bd0c23c1c0 = []byte{ - // 775 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x96, 0x4f, 0x4f, 0xd4, 0x4e, - 0x18, 0xc7, 0xb7, 0xb0, 0xec, 0xef, 0xb7, 0x83, 0x07, 0x1d, 0x48, 0x5c, 0x1a, 0x2d, 0xeb, 0x48, - 0x08, 0x02, 0x3b, 0x03, 0x8b, 0x98, 0xf8, 0xe7, 0x00, 0x4b, 0x3c, 0xac, 0x5e, 0xb4, 0x17, 0x13, - 0x2f, 0x9b, 0x6e, 0xb7, 0x59, 0x1b, 0xdb, 0x4e, 0x69, 0x0b, 0x61, 0x25, 0x1c, 0xf4, 0x05, 0x18, - 0x13, 0xa3, 0x27, 0x4d, 0x3c, 0xfa, 0x4a, 0x0c, 0x47, 0x12, 0x2f, 0xc6, 0x03, 0x31, 0xe0, 0x0b, - 0x31, 0xf3, 0xa7, 0xdd, 0xae, 0x4a, 0x5b, 0xe2, 0x89, 0x9d, 0x67, 0x9e, 0x67, 0xbe, 0x9f, 0x67, - 0xfa, 0xcc, 0x37, 0x80, 0xf9, 0xde, 0xc0, 0xb5, 0xbc, 0xd0, 0xa6, 0xde, 0xde, 0xe0, 0x05, 0x49, - 0x16, 0xc4, 0x0e, 0x28, 0xd9, 0xde, 0xb1, 0x82, 0x01, 0xf6, 0x03, 0x1a, 0x51, 0xa8, 0xa6, 0xf3, - 0x70, 0xb2, 0xc0, 0x76, 0x40, 0xd5, 0xe9, 0x3e, 0xed, 0x53, 0x9e, 0x46, 0xd8, 0x2f, 0x51, 0xa1, - 0xce, 0x98, 0x34, 0x74, 0x69, 0xd8, 0x11, 0x1b, 0x62, 0x21, 0xb7, 0xae, 0xf4, 0x29, 0xed, 0x3b, - 0x16, 0x31, 0x7c, 0x9b, 0x18, 0x9e, 0x47, 0x23, 0x23, 0xb2, 0xa9, 0x17, 0xef, 0xce, 0x65, 0x20, - 0xd9, 0x41, 0x7c, 0xbc, 0x26, 0x4e, 0x24, 0x5d, 0x23, 0xb4, 0xc8, 0xee, 0x6a, 0xd7, 0x8a, 0x8c, - 0x55, 0x62, 0x52, 0xdb, 0x13, 0xfb, 0x68, 0x1a, 0xc0, 0xc7, 0x8c, 0xff, 0x91, 0x11, 0x18, 0x6e, - 0xa8, 0x5b, 0xdb, 0x3b, 0x56, 0x18, 0xa1, 0x27, 0x60, 0x6a, 0x24, 0x1a, 0xfa, 0xd4, 0x0b, 0x2d, - 0xb8, 0x01, 0x2a, 0x3e, 0x8f, 0xd4, 0x94, 0xba, 0xb2, 0x30, 0xd9, 0x44, 0xf8, 0xec, 0x76, 0xb1, - 0xa8, 0x6d, 0x95, 0x0f, 0x8f, 0x67, 0x4b, 0xba, 0xac, 0x43, 0x53, 0xe0, 0x92, 0x38, 0xd8, 0x31, - 0xbc, 0x44, 0x4d, 0x8f, 0x19, 0x44, 0x50, 0x8a, 0xdd, 0x03, 0x13, 0x3e, 0x0b, 0xd4, 0x94, 0xfa, - 0xf8, 0xc2, 0x64, 0xb3, 0x9e, 0xa9, 0xe5, 0x18, 0x9e, 0x54, 0x12, 0x45, 0x68, 0x09, 0x5c, 0x4c, - 0xce, 0x94, 0x3a, 0xf0, 0x32, 0xf8, 0x8f, 0x6d, 0x76, 0xec, 0x1e, 0xe7, 0xaf, 0xea, 0x15, 0xb6, - 0x6c, 0xf7, 0x50, 0x3b, 0x45, 0x95, 0xe8, 0xdf, 0x04, 0x65, 0xb6, 0x2d, 0x5b, 0xcd, 0x95, 0xd7, - 0x79, 0x36, 0xba, 0x03, 0x66, 0x92, 0xa3, 0x5a, 0x03, 0x9d, 0x3a, 0x8e, 0xe1, 0xfb, 0x31, 0xc0, - 0x55, 0x00, 0x02, 0x11, 0x19, 0x32, 0x54, 0x65, 0xa4, 0xdd, 0x43, 0x3a, 0x50, 0xff, 0x56, 0xfb, - 0x4f, 0x3c, 0xcb, 0x71, 0x6b, 0x81, 0x6d, 0x5a, 0xb9, 0x17, 0x71, 0x3f, 0xfe, 0x12, 0x22, 0x5b, - 0x2a, 0x13, 0x30, 0xe1, 0xb3, 0x80, 0x94, 0x9e, 0xc1, 0x72, 0x4a, 0xd9, 0x4c, 0x61, 0x39, 0x53, - 0x78, 0x8b, 0xda, 0x9e, 0x2e, 0xf2, 0xd0, 0x4b, 0x45, 0xde, 0xfe, 0x16, 0x0d, 0xa3, 0x3c, 0x51, - 0xb8, 0x01, 0xc6, 0x0d, 0x37, 0xaa, 0x8d, 0xb1, 0x60, 0x0b, 0xb3, 0x8f, 0xf8, 0xfd, 0x78, 0x76, - 0xbe, 0x6f, 0x47, 0xcf, 0x76, 0xba, 0xd8, 0xa4, 0xae, 0x7c, 0x14, 0xf2, 0x4f, 0x23, 0xec, 0x3d, - 0x27, 0xd1, 0xc0, 0xb7, 0x42, 0xdc, 0xf6, 0x22, 0x9d, 0x95, 0x42, 0x08, 0xca, 0xa1, 0xe5, 0x38, - 0xb5, 0xf1, 0xba, 0xb2, 0xf0, 0xbf, 0xce, 0x7f, 0xa3, 0x96, 0x6c, 0x5c, 0x20, 0xc8, 0x4e, 0x1a, - 0xa0, 0x6c, 0xd2, 0x30, 0xca, 0x6f, 0x84, 0xa7, 0x21, 0x2c, 0x9f, 0xc1, 0x96, 0x63, 0xd8, 0xae, - 0xd5, 0xcb, 0xbd, 0x3e, 0x13, 0x4c, 0x8f, 0xe6, 0x4b, 0xd9, 0x87, 0x60, 0xd2, 0x14, 0xa1, 0x0e, - 0xeb, 0x94, 0x17, 0xb5, 0x16, 0xcf, 0xd1, 0x25, 0x90, 0xe5, 0x9b, 0x6e, 0xd4, 0x7c, 0x5d, 0x05, - 0x13, 0x5c, 0x05, 0xbe, 0x53, 0x40, 0x45, 0xbc, 0x32, 0x88, 0xb3, 0xc6, 0xe1, 0xcf, 0x07, 0xae, - 0x92, 0xc2, 0xf9, 0xa2, 0x05, 0xb4, 0xf8, 0xea, 0xeb, 0xcf, 0xb7, 0x63, 0x73, 0x10, 0x91, 0x0c, - 0xdb, 0x11, 0x8f, 0x1c, 0xbe, 0x57, 0x00, 0x18, 0x3e, 0x68, 0xd8, 0xc8, 0xd7, 0x4a, 0xb9, 0x81, - 0x8a, 0x8b, 0xa6, 0x4b, 0xb2, 0x1b, 0x9c, 0xec, 0x3a, 0xbc, 0x96, 0x49, 0xc6, 0x49, 0x3e, 0x2a, - 0xa0, 0x9a, 0x9c, 0x00, 0x97, 0x0b, 0x09, 0xc5, 0x58, 0x8d, 0x82, 0xd9, 0x92, 0x6a, 0x8d, 0x53, - 0x35, 0xe0, 0x52, 0x2e, 0x15, 0xd9, 0x97, 0xc3, 0x74, 0x00, 0xbf, 0x28, 0x29, 0x27, 0x4c, 0x1c, - 0x00, 0xae, 0x17, 0x92, 0xfe, 0xdd, 0x6d, 0xd4, 0x5b, 0xe7, 0x2d, 0x93, 0xe8, 0x9b, 0x1c, 0xfd, - 0x2e, 0xbc, 0x9d, 0x8b, 0xde, 0xe9, 0x0e, 0x3a, 0xd2, 0xbe, 0xc8, 0xfe, 0xd0, 0xd9, 0x0e, 0xe0, - 0xa7, 0x64, 0x02, 0x98, 0x1f, 0x14, 0x99, 0x80, 0x94, 0x3d, 0x15, 0x99, 0x80, 0xb4, 0x3f, 0x15, - 0xbc, 0x6b, 0x56, 0x92, 0xba, 0xeb, 0x0f, 0xf1, 0x2c, 0x30, 0x83, 0x28, 0x30, 0x0b, 0x29, 0x2b, - 0x2b, 0x30, 0x0b, 0x69, 0xd7, 0x41, 0x4d, 0xce, 0xb7, 0x0c, 0x17, 0xb3, 0xf8, 0x98, 0xe1, 0xa4, - 0xf0, 0x3e, 0x2b, 0xe0, 0x42, 0xda, 0x4b, 0x60, 0xfe, 0x8b, 0x1d, 0x75, 0x29, 0x75, 0xa5, 0x78, - 0x81, 0xe4, 0x5c, 0xe7, 0x9c, 0x04, 0x36, 0x32, 0x39, 0x45, 0xd1, 0x10, 0xb5, 0xf5, 0xe0, 0xf0, - 0x44, 0x53, 0x8e, 0x4e, 0x34, 0xe5, 0xc7, 0x89, 0xa6, 0xbc, 0x39, 0xd5, 0x4a, 0x47, 0xa7, 0x5a, - 0xe9, 0xdb, 0xa9, 0x56, 0x7a, 0xba, 0x92, 0xb2, 0xb7, 0x33, 0x8e, 0xdc, 0x5d, 0x23, 0x7b, 0xfc, - 0x5c, 0x6e, 0x76, 0xdd, 0x0a, 0xff, 0xaf, 0x64, 0xed, 0x57, 0x00, 0x00, 0x00, 0xff, 0xff, 0x3d, - 0x02, 0x68, 0x7d, 0x70, 0x09, 0x00, 0x00, + // 789 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x96, 0xcf, 0x4f, 0x13, 0x5b, + 0x14, 0xc7, 0x3b, 0x50, 0xfa, 0x5e, 0x0f, 0x2f, 0x2f, 0xef, 0x5d, 0x50, 0xcb, 0x44, 0x4b, 0x1d, + 0x09, 0x41, 0xa0, 0xf7, 0x42, 0x11, 0x13, 0x7f, 0x2c, 0xa0, 0xb0, 0xa9, 0x6e, 0x70, 0x5c, 0x98, + 0xb8, 0xb0, 0x99, 0x4e, 0x27, 0x75, 0xe2, 0x74, 0xee, 0x30, 0x33, 0x10, 0x2a, 0x61, 0xa1, 0x7f, + 0x81, 0x89, 0xd1, 0x85, 0xd1, 0xbd, 0x0b, 0xff, 0x0e, 0xc3, 0x92, 0xc4, 0x8d, 0x71, 0x41, 0x0c, + 0xf8, 0x87, 0x98, 0xfb, 0xa3, 0xd3, 0x29, 0x4a, 0x67, 0x1a, 0x57, 0xf4, 0x9e, 0x7b, 0xbe, 0xe7, + 0x7c, 0xee, 0x9d, 0x7b, 0xbe, 0x01, 0x66, 0x9b, 0x9d, 0xb6, 0xe5, 0x06, 0x36, 0x75, 0xf7, 0x3a, + 0xcf, 0x49, 0xb4, 0x20, 0xb6, 0x4f, 0xc9, 0xf6, 0x8e, 0xe5, 0x77, 0xb0, 0xe7, 0xd3, 0x90, 0x22, + 0x35, 0x9e, 0x87, 0xa3, 0x05, 0xb6, 0x7d, 0xaa, 0x4e, 0xb6, 0x68, 0x8b, 0xf2, 0x34, 0xc2, 0x7e, + 0x09, 0x85, 0x3a, 0x65, 0xd2, 0xa0, 0x4d, 0x83, 0xba, 0xd8, 0x10, 0x0b, 0xb9, 0x75, 0xb9, 0x45, + 0x69, 0xcb, 0xb1, 0x88, 0xe1, 0xd9, 0xc4, 0x70, 0x5d, 0x1a, 0x1a, 0xa1, 0x4d, 0xdd, 0xee, 0xee, + 0xcc, 0x00, 0x24, 0xdb, 0xef, 0x96, 0x2f, 0x8a, 0x8a, 0xa4, 0x61, 0x04, 0x16, 0xd9, 0x5d, 0x6e, + 0x58, 0xa1, 0xb1, 0x4c, 0x4c, 0x6a, 0xbb, 0x62, 0x5f, 0x9b, 0x04, 0xf4, 0x80, 0xf1, 0x6f, 0x19, + 0xbe, 0xd1, 0x0e, 0x74, 0x6b, 0x7b, 0xc7, 0x0a, 0x42, 0xed, 0x11, 0x4c, 0xf4, 0x45, 0x03, 0x8f, + 0xba, 0x81, 0x85, 0xd6, 0x20, 0xe7, 0xf1, 0x48, 0x41, 0x29, 0x29, 0x73, 0xe3, 0x15, 0x0d, 0x9f, + 0x7f, 0x5c, 0x2c, 0xb4, 0xd5, 0xec, 0xe1, 0xf1, 0x74, 0x46, 0x97, 0x3a, 0x6d, 0x02, 0xfe, 0x17, + 0x85, 0x1d, 0xc3, 0x8d, 0xba, 0xe9, 0x5d, 0x06, 0x11, 0x94, 0xcd, 0xee, 0xc2, 0x98, 0xc7, 0x02, + 0x05, 0xa5, 0x34, 0x3a, 0x37, 0x5e, 0x29, 0x0d, 0xec, 0xe5, 0x18, 0xae, 0xec, 0x24, 0x44, 0xda, + 0x02, 0xfc, 0x17, 0xd5, 0x94, 0x7d, 0xd0, 0x25, 0xf8, 0x8b, 0x6d, 0xd6, 0xed, 0x26, 0xe7, 0xcf, + 0xeb, 0x39, 0xb6, 0xac, 0x35, 0xb5, 0x5a, 0x8c, 0x2a, 0xea, 0x7f, 0x03, 0xb2, 0x6c, 0x5b, 0x1e, + 0x35, 0xb1, 0xbd, 0xce, 0xb3, 0xb5, 0xdb, 0x30, 0x15, 0x95, 0xaa, 0x76, 0x74, 0xea, 0x38, 0x86, + 0xe7, 0x75, 0x01, 0xae, 0x00, 0xf8, 0x22, 0xd2, 0x63, 0xc8, 0xcb, 0x48, 0xad, 0xa9, 0xe9, 0xa0, + 0xfe, 0x4e, 0xfb, 0x47, 0x3c, 0x4b, 0x70, 0x81, 0xd7, 0x7c, 0xe8, 0xd1, 0x70, 0xcb, 0xb7, 0x4d, + 0x2b, 0xf1, 0x32, 0x9e, 0xc0, 0xc5, 0xb3, 0x0a, 0x49, 0xb0, 0x09, 0x63, 0x1e, 0x0b, 0x08, 0x41, + 0x15, 0xb3, 0xfb, 0xfe, 0x76, 0x3c, 0x3d, 0xdb, 0xb2, 0xc3, 0xa7, 0x3b, 0x0d, 0x6c, 0xd2, 0xb6, + 0x7c, 0xbf, 0xf2, 0x4f, 0x39, 0x68, 0x3e, 0x23, 0x61, 0xc7, 0xb3, 0x02, 0xbc, 0x69, 0x99, 0xba, + 0x10, 0x6b, 0x2f, 0x14, 0xf9, 0x69, 0x36, 0x68, 0x10, 0x26, 0xd1, 0xa0, 0x35, 0x18, 0x35, 0xda, + 0x61, 0x61, 0x64, 0xe8, 0x8e, 0x35, 0x37, 0xd4, 0x99, 0x14, 0x21, 0xc8, 0x06, 0x96, 0xe3, 0x14, + 0x46, 0x4b, 0xca, 0xdc, 0xdf, 0x3a, 0xff, 0xad, 0x55, 0xe5, 0x07, 0x17, 0x08, 0xf2, 0x78, 0x65, + 0xc8, 0x9a, 0x34, 0x08, 0xe5, 0x05, 0x4f, 0x61, 0x39, 0x8b, 0x6c, 0x72, 0xb0, 0x9c, 0x1c, 0xbc, + 0x41, 0x6d, 0x57, 0xe7, 0x69, 0x1a, 0x96, 0x33, 0xb2, 0xe1, 0x18, 0x76, 0xdb, 0x6a, 0x26, 0xde, + 0xab, 0x09, 0x93, 0xfd, 0xf9, 0xb2, 0xed, 0x7d, 0x18, 0x37, 0x45, 0xa8, 0xce, 0x4e, 0x2a, 0xee, + 0x76, 0x7e, 0x88, 0x53, 0x82, 0x94, 0xaf, 0xb7, 0xc3, 0xca, 0xbb, 0x3c, 0x8c, 0xf1, 0x2e, 0xe8, + 0x8d, 0x02, 0x39, 0x31, 0x82, 0x08, 0x0f, 0x7a, 0x2b, 0xbf, 0x4e, 0xbf, 0x4a, 0x52, 0xe7, 0x8b, + 0x23, 0x68, 0xf3, 0x2f, 0xbf, 0xfc, 0x78, 0x3d, 0x32, 0x83, 0x34, 0x32, 0xc0, 0x93, 0x84, 0x03, + 0xa0, 0xb7, 0x0a, 0x40, 0x6f, 0xda, 0x51, 0x39, 0xb9, 0x57, 0xcc, 0x2a, 0x54, 0x9c, 0x36, 0x5d, + 0x92, 0x5d, 0xe7, 0x64, 0xd7, 0xd0, 0xd5, 0x81, 0x64, 0x9c, 0xe4, 0x83, 0x02, 0xf9, 0xa8, 0x02, + 0x5a, 0x4c, 0xd5, 0xa8, 0x8b, 0x55, 0x4e, 0x99, 0x2d, 0xa9, 0x56, 0x38, 0x55, 0x19, 0x2d, 0x24, + 0x52, 0x91, 0x7d, 0xf9, 0x98, 0x0e, 0xd0, 0x67, 0x25, 0x66, 0x93, 0x91, 0x3d, 0xa0, 0xd5, 0x54, + 0xad, 0xcf, 0x5a, 0x91, 0x7a, 0x73, 0x58, 0x99, 0x44, 0x5f, 0xe7, 0xe8, 0x77, 0xd0, 0xad, 0x44, + 0xf4, 0x7a, 0xa3, 0x53, 0x97, 0xde, 0x46, 0xf6, 0x7b, 0xb6, 0x77, 0x80, 0x3e, 0x29, 0xf0, 0x6f, + 0xbf, 0xc3, 0xa0, 0xe5, 0x44, 0x9a, 0xb3, 0xfe, 0xa5, 0x56, 0x86, 0x91, 0x0c, 0x75, 0xef, 0x4c, + 0x12, 0xbb, 0xf7, 0xf7, 0xdd, 0x77, 0xc1, 0xcc, 0x22, 0xc5, 0xbb, 0x88, 0xd9, 0x5a, 0x8a, 0x77, + 0x11, 0x77, 0x20, 0xad, 0xc2, 0xf9, 0x16, 0xd1, 0xfc, 0x20, 0x3e, 0x66, 0x3e, 0x31, 0xbc, 0x8f, + 0x0a, 0xfc, 0x13, 0xf7, 0x15, 0x94, 0x3c, 0xbd, 0xfd, 0x8e, 0xa5, 0x2e, 0xa5, 0x17, 0x48, 0xce, + 0x55, 0xce, 0x49, 0x50, 0x79, 0x20, 0xa7, 0x10, 0xf5, 0x50, 0xab, 0xf7, 0x0e, 0x4f, 0x8a, 0xca, + 0xd1, 0x49, 0x51, 0xf9, 0x7e, 0x52, 0x54, 0x5e, 0x9d, 0x16, 0x33, 0x47, 0xa7, 0xc5, 0xcc, 0xd7, + 0xd3, 0x62, 0xe6, 0xf1, 0x52, 0xcc, 0xea, 0xce, 0x29, 0xb9, 0xbb, 0x42, 0xf6, 0x78, 0x5d, 0x6e, + 0x7c, 0x8d, 0x1c, 0xff, 0xf7, 0x65, 0xe5, 0x67, 0x00, 0x00, 0x00, 0xff, 0xff, 0x48, 0x72, 0xb6, + 0x2d, 0x99, 0x09, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -739,20 +733,20 @@ const _ = grpc.SupportPackageIsVersion4 // // 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 { - // Param queries the parameters of the module. + // Params queries the parameters of the IRO module. Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) - // Plans + // QueryPlans retrieves all available plans. QueryPlans(ctx context.Context, in *QueryPlansRequest, opts ...grpc.CallOption) (*QueryPlansResponse, error) - // Plan returns the plan for the specified plan ID. + // QueryPlan retrieves the plan for the specified plan ID. QueryPlan(ctx context.Context, in *QueryPlanRequest, opts ...grpc.CallOption) (*QueryPlanResponse, error) - // PlanByRollapp returns the plans for the specified rollapp ID. + // QueryPlanByRollapp retrieves the plans for the specified rollapp ID. QueryPlanByRollapp(ctx context.Context, in *QueryPlanByRollappRequest, opts ...grpc.CallOption) (*QueryPlanByRollappResponse, error) - // Price returns the current price for 1 IRO token for the specified plan ID. - QueryPrice(ctx context.Context, in *QueryPriceRequest, opts ...grpc.CallOption) (*QueryPriceResponse, error) - // Cost returns the expected cost for buying or selling the specified amount - // of shares. + // QuerySpotPrice retrieves the current spot price for the specified plan ID. + // The result is the price of 1 IRO token (not iro's base denom) + QuerySpotPrice(ctx context.Context, in *QuerySpotPriceRequest, opts ...grpc.CallOption) (*QuerySpotPriceResponse, error) + // QueryCost retrieves the expected cost for buying or selling the specified amount of shares. QueryCost(ctx context.Context, in *QueryCostRequest, opts ...grpc.CallOption) (*QueryCostResponse, error) - // Claimed returns the claimed amount thus far for the specified plan ID. + // QueryClaimed retrieves the claimed amount thus far for the specified plan ID. QueryClaimed(ctx context.Context, in *QueryClaimedRequest, opts ...grpc.CallOption) (*QueryClaimedResponse, error) } @@ -800,9 +794,9 @@ func (c *queryClient) QueryPlanByRollapp(ctx context.Context, in *QueryPlanByRol return out, nil } -func (c *queryClient) QueryPrice(ctx context.Context, in *QueryPriceRequest, opts ...grpc.CallOption) (*QueryPriceResponse, error) { - out := new(QueryPriceResponse) - err := c.cc.Invoke(ctx, "/dymensionxyz.dymension.iro.Query/QueryPrice", in, out, opts...) +func (c *queryClient) QuerySpotPrice(ctx context.Context, in *QuerySpotPriceRequest, opts ...grpc.CallOption) (*QuerySpotPriceResponse, error) { + out := new(QuerySpotPriceResponse) + err := c.cc.Invoke(ctx, "/dymensionxyz.dymension.iro.Query/QuerySpotPrice", in, out, opts...) if err != nil { return nil, err } @@ -829,20 +823,20 @@ func (c *queryClient) QueryClaimed(ctx context.Context, in *QueryClaimedRequest, // QueryServer is the server API for Query service. type QueryServer interface { - // Param queries the parameters of the module. + // Params queries the parameters of the IRO module. Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) - // Plans + // QueryPlans retrieves all available plans. QueryPlans(context.Context, *QueryPlansRequest) (*QueryPlansResponse, error) - // Plan returns the plan for the specified plan ID. + // QueryPlan retrieves the plan for the specified plan ID. QueryPlan(context.Context, *QueryPlanRequest) (*QueryPlanResponse, error) - // PlanByRollapp returns the plans for the specified rollapp ID. + // QueryPlanByRollapp retrieves the plans for the specified rollapp ID. QueryPlanByRollapp(context.Context, *QueryPlanByRollappRequest) (*QueryPlanByRollappResponse, error) - // Price returns the current price for 1 IRO token for the specified plan ID. - QueryPrice(context.Context, *QueryPriceRequest) (*QueryPriceResponse, error) - // Cost returns the expected cost for buying or selling the specified amount - // of shares. + // QuerySpotPrice retrieves the current spot price for the specified plan ID. + // The result is the price of 1 IRO token (not iro's base denom) + QuerySpotPrice(context.Context, *QuerySpotPriceRequest) (*QuerySpotPriceResponse, error) + // QueryCost retrieves the expected cost for buying or selling the specified amount of shares. QueryCost(context.Context, *QueryCostRequest) (*QueryCostResponse, error) - // Claimed returns the claimed amount thus far for the specified plan ID. + // QueryClaimed retrieves the claimed amount thus far for the specified plan ID. QueryClaimed(context.Context, *QueryClaimedRequest) (*QueryClaimedResponse, error) } @@ -862,8 +856,8 @@ func (*UnimplementedQueryServer) QueryPlan(ctx context.Context, req *QueryPlanRe func (*UnimplementedQueryServer) QueryPlanByRollapp(ctx context.Context, req *QueryPlanByRollappRequest) (*QueryPlanByRollappResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method QueryPlanByRollapp not implemented") } -func (*UnimplementedQueryServer) QueryPrice(ctx context.Context, req *QueryPriceRequest) (*QueryPriceResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method QueryPrice not implemented") +func (*UnimplementedQueryServer) QuerySpotPrice(ctx context.Context, req *QuerySpotPriceRequest) (*QuerySpotPriceResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method QuerySpotPrice not implemented") } func (*UnimplementedQueryServer) QueryCost(ctx context.Context, req *QueryCostRequest) (*QueryCostResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method QueryCost not implemented") @@ -948,20 +942,20 @@ func _Query_QueryPlanByRollapp_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } -func _Query_QueryPrice_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryPriceRequest) +func _Query_QuerySpotPrice_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QuerySpotPriceRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(QueryServer).QueryPrice(ctx, in) + return srv.(QueryServer).QuerySpotPrice(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/dymensionxyz.dymension.iro.Query/QueryPrice", + FullMethod: "/dymensionxyz.dymension.iro.Query/QuerySpotPrice", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QueryServer).QueryPrice(ctx, req.(*QueryPriceRequest)) + return srv.(QueryServer).QuerySpotPrice(ctx, req.(*QuerySpotPriceRequest)) } return interceptor(ctx, in, info, handler) } @@ -1023,8 +1017,8 @@ var _Query_serviceDesc = grpc.ServiceDesc{ Handler: _Query_QueryPlanByRollapp_Handler, }, { - MethodName: "QueryPrice", - Handler: _Query_QueryPrice_Handler, + MethodName: "QuerySpotPrice", + Handler: _Query_QuerySpotPrice_Handler, }, { MethodName: "QueryCost", @@ -1285,7 +1279,7 @@ func (m *QueryPlanByRollappResponse) MarshalToSizedBuffer(dAtA []byte) (int, err return len(dAtA) - i, nil } -func (m *QueryPriceRequest) Marshal() (dAtA []byte, err error) { +func (m *QuerySpotPriceRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -1295,12 +1289,12 @@ func (m *QueryPriceRequest) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *QueryPriceRequest) MarshalTo(dAtA []byte) (int, error) { +func (m *QuerySpotPriceRequest) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *QueryPriceRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *QuerySpotPriceRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -1315,7 +1309,7 @@ func (m *QueryPriceRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *QueryPriceResponse) Marshal() (dAtA []byte, err error) { +func (m *QuerySpotPriceResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -1325,28 +1319,26 @@ func (m *QueryPriceResponse) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *QueryPriceResponse) MarshalTo(dAtA []byte) (int, error) { +func (m *QuerySpotPriceResponse) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *QueryPriceResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *QuerySpotPriceResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - if m.Price != nil { - { - size, err := m.Price.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintQuery(dAtA, i, uint64(size)) + { + size := m.Price.Size() + i -= size + if _, err := m.Price.MarshalTo(dAtA[i:]); err != nil { + return 0, err } - i-- - dAtA[i] = 0xa + i = encodeVarintQuery(dAtA, i, uint64(size)) } + i-- + dAtA[i] = 0xa return len(dAtA) - i, nil } @@ -1607,7 +1599,7 @@ func (m *QueryPlanByRollappResponse) Size() (n int) { return n } -func (m *QueryPriceRequest) Size() (n int) { +func (m *QuerySpotPriceRequest) Size() (n int) { if m == nil { return 0 } @@ -1620,16 +1612,14 @@ func (m *QueryPriceRequest) Size() (n int) { return n } -func (m *QueryPriceResponse) Size() (n int) { +func (m *QuerySpotPriceResponse) Size() (n int) { if m == nil { return 0 } var l int _ = l - if m.Price != nil { - l = m.Price.Size() - n += 1 + l + sovQuery(uint64(l)) - } + l = m.Price.Size() + n += 1 + l + sovQuery(uint64(l)) return n } @@ -2299,7 +2289,7 @@ func (m *QueryPlanByRollappResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *QueryPriceRequest) Unmarshal(dAtA []byte) error { +func (m *QuerySpotPriceRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -2322,10 +2312,10 @@ func (m *QueryPriceRequest) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: QueryPriceRequest: wiretype end group for non-group") + return fmt.Errorf("proto: QuerySpotPriceRequest: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: QueryPriceRequest: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: QuerySpotPriceRequest: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -2381,7 +2371,7 @@ func (m *QueryPriceRequest) Unmarshal(dAtA []byte) error { } return nil } -func (m *QueryPriceResponse) Unmarshal(dAtA []byte) error { +func (m *QuerySpotPriceResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -2404,17 +2394,17 @@ func (m *QueryPriceResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: QueryPriceResponse: wiretype end group for non-group") + return fmt.Errorf("proto: QuerySpotPriceResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: QueryPriceResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: QuerySpotPriceResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Price", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowQuery @@ -2424,24 +2414,22 @@ func (m *QueryPriceResponse) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthQuery } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthQuery } if postIndex > l { return io.ErrUnexpectedEOF } - if m.Price == nil { - m.Price = &types.Coin{} - } if err := m.Price.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } diff --git a/x/iro/types/query.pb.gw.go b/x/iro/types/query.pb.gw.go index 895afedcc..1dc8e3bd1 100644 --- a/x/iro/types/query.pb.gw.go +++ b/x/iro/types/query.pb.gw.go @@ -177,8 +177,8 @@ func local_request_Query_QueryPlanByRollapp_0(ctx context.Context, marshaler run } -func request_Query_QueryPrice_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryPriceRequest +func request_Query_QuerySpotPrice_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QuerySpotPriceRequest var metadata runtime.ServerMetadata var ( @@ -199,13 +199,13 @@ func request_Query_QueryPrice_0(ctx context.Context, marshaler runtime.Marshaler return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "plan_id", err) } - msg, err := client.QueryPrice(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + msg, err := client.QuerySpotPrice(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } -func local_request_Query_QueryPrice_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryPriceRequest +func local_request_Query_QuerySpotPrice_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QuerySpotPriceRequest var metadata runtime.ServerMetadata var ( @@ -226,7 +226,7 @@ func local_request_Query_QueryPrice_0(ctx context.Context, marshaler runtime.Mar return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "plan_id", err) } - msg, err := server.QueryPrice(ctx, &protoReq) + msg, err := server.QuerySpotPrice(ctx, &protoReq) return msg, metadata, err } @@ -455,7 +455,7 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) - mux.Handle("GET", pattern_Query_QueryPrice_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_Query_QuerySpotPrice_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream @@ -466,7 +466,7 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_Query_QueryPrice_0(rctx, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_Query_QuerySpotPrice_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 { @@ -474,7 +474,7 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv return } - forward_Query_QueryPrice_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Query_QuerySpotPrice_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) @@ -645,7 +645,7 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) - mux.Handle("GET", pattern_Query_QueryPrice_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_Query_QuerySpotPrice_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) @@ -654,14 +654,14 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_Query_QueryPrice_0(rctx, inboundMarshaler, client, req, pathParams) + resp, md, err := request_Query_QuerySpotPrice_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_QueryPrice_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Query_QuerySpotPrice_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) @@ -717,7 +717,7 @@ var ( pattern_Query_QueryPlanByRollapp_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"dymensionxyz", "dymension", "iro", "plans_by_rollapp", "rollapp_id"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_QueryPrice_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"dymensionxyz", "dymension", "iro", "price", "plan_id"}, "", runtime.AssumeColonVerbOpt(false))) + pattern_Query_QuerySpotPrice_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"dymensionxyz", "dymension", "iro", "price", "plan_id"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_QueryCost_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"dymensionxyz", "dymension", "iro", "cost", "plan_id"}, "", runtime.AssumeColonVerbOpt(false))) @@ -733,7 +733,7 @@ var ( forward_Query_QueryPlanByRollapp_0 = runtime.ForwardResponseMessage - forward_Query_QueryPrice_0 = runtime.ForwardResponseMessage + forward_Query_QuerySpotPrice_0 = runtime.ForwardResponseMessage forward_Query_QueryCost_0 = runtime.ForwardResponseMessage diff --git a/x/iro/types/tx.pb.go b/x/iro/types/tx.pb.go index 12e1a8135..365e9093b 100644 --- a/x/iro/types/tx.pb.go +++ b/x/iro/types/tx.pb.go @@ -271,8 +271,8 @@ type MsgBuy struct { PlanId string `protobuf:"bytes,2,opt,name=plan_id,json=planId,proto3" json:"plan_id,omitempty"` // The amount of tokens to buy. Amount github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,3,opt,name=amount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"amount"` - // The expected output amount. - ExpectedOutAmount github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,4,opt,name=expected_out_amount,json=expectedOutAmount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"expected_out_amount"` + // The maximum cost this buy action can incur. + MaxCostAmount github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,4,opt,name=max_cost_amount,json=maxCostAmount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"max_cost_amount"` } func (m *MsgBuy) Reset() { *m = MsgBuy{} } @@ -365,8 +365,8 @@ type MsgSell struct { PlanId string `protobuf:"bytes,2,opt,name=plan_id,json=planId,proto3" json:"plan_id,omitempty"` // The amount of tokens to sell. Amount github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,3,opt,name=amount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"amount"` - // The expected output amount. - ExpectedOutAmount github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,4,opt,name=expected_out_amount,json=expectedOutAmount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"expected_out_amount"` + // The minimum income this sell action can incur. + MinIncomeAmount github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,4,opt,name=min_income_amount,json=minIncomeAmount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"min_income_amount"` } func (m *MsgSell) Reset() { *m = MsgSell{} } @@ -560,60 +560,61 @@ func init() { } var fileDescriptor_41b9ae3e091bbd60 = []byte{ - // 845 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x56, 0xcf, 0x6f, 0xdc, 0x44, - 0x14, 0x8e, 0x93, 0xcd, 0xa6, 0xfb, 0x9a, 0x34, 0xe9, 0xb4, 0x55, 0xb6, 0x96, 0xd8, 0x54, 0x6e, - 0x85, 0x42, 0x4a, 0xed, 0xfc, 0x90, 0x38, 0xe4, 0xd6, 0x8d, 0x04, 0x0a, 0xea, 0x0a, 0xb4, 0xa1, - 0x12, 0x3f, 0x24, 0xac, 0xb1, 0x3d, 0x38, 0x03, 0xf6, 0x8c, 0xe5, 0x19, 0x6f, 0x76, 0x39, 0x21, - 0x24, 0x0e, 0xdc, 0x7a, 0xe4, 0xcc, 0x5f, 0xd0, 0x03, 0x7f, 0x44, 0x8f, 0x15, 0x27, 0xc4, 0xa1, - 0xa0, 0xe4, 0xd0, 0x7f, 0x81, 0x23, 0x9a, 0x19, 0xdb, 0xd9, 0x14, 0x65, 0x77, 0x03, 0x27, 0x4e, - 0xf6, 0xf3, 0xfb, 0xde, 0x37, 0x6f, 0xbe, 0xf9, 0xe6, 0xc9, 0x70, 0x3f, 0x1a, 0xa5, 0x84, 0x09, - 0xca, 0xd9, 0x70, 0xf4, 0xad, 0x57, 0x07, 0x1e, 0xcd, 0xb9, 0x27, 0x87, 0x6e, 0x96, 0x73, 0xc9, - 0x91, 0x3d, 0x0e, 0x72, 0xeb, 0xc0, 0xa5, 0x39, 0xb7, 0x6f, 0xc7, 0x3c, 0xe6, 0x1a, 0xe6, 0xa9, - 0x37, 0x53, 0x61, 0xdf, 0x0d, 0xb9, 0x48, 0xb9, 0xf0, 0x4d, 0xc2, 0x04, 0x65, 0x6a, 0xdd, 0x44, - 0x5e, 0x2a, 0x62, 0x6f, 0xb0, 0xa3, 0x1e, 0x65, 0xe2, 0xc1, 0x84, 0x56, 0x68, 0x5e, 0x31, 0x6f, - 0xc4, 0x9c, 0xc7, 0x09, 0xf1, 0x74, 0x14, 0x14, 0x5f, 0x79, 0x92, 0xa6, 0x44, 0x48, 0x9c, 0x66, - 0x25, 0xa0, 0x53, 0xf2, 0x07, 0x58, 0x10, 0x6f, 0xb0, 0x13, 0x10, 0x89, 0x77, 0xbc, 0x90, 0x53, - 0x66, 0xf2, 0xce, 0xcf, 0x16, 0xac, 0xf6, 0x44, 0xfc, 0x34, 0x8b, 0xb0, 0x24, 0x1f, 0xe3, 0x1c, - 0xa7, 0x02, 0xbd, 0x07, 0x2d, 0x5c, 0xc8, 0x63, 0x9e, 0x53, 0x39, 0x6a, 0x5b, 0xf7, 0xac, 0xcd, - 0x56, 0xb7, 0xfd, 0xeb, 0x2f, 0x8f, 0x6e, 0x97, 0x8d, 0x3f, 0x8e, 0xa2, 0x9c, 0x08, 0x71, 0x24, - 0x73, 0xca, 0xe2, 0xfe, 0x39, 0x14, 0x7d, 0x00, 0xc0, 0xc8, 0x89, 0x9f, 0x69, 0x96, 0xf6, 0xfc, - 0x3d, 0x6b, 0xf3, 0xfa, 0xae, 0xe3, 0x5e, 0xae, 0x96, 0x6b, 0xd6, 0xeb, 0x36, 0x5e, 0xbc, 0xda, - 0x98, 0xeb, 0xb7, 0x18, 0x39, 0x31, 0x1f, 0xf6, 0x6f, 0x7c, 0xff, 0xfa, 0xf9, 0xd6, 0x39, 0xb1, - 0x73, 0x17, 0xd6, 0xdf, 0xe8, 0xb1, 0x4f, 0x44, 0xc6, 0x99, 0x20, 0xce, 0x4f, 0x0d, 0x58, 0xe9, - 0x89, 0xf8, 0x20, 0x27, 0x2a, 0x97, 0x60, 0x86, 0x5c, 0x58, 0xe4, 0x27, 0x8c, 0xe4, 0x53, 0x3b, - 0x37, 0x30, 0xf4, 0x16, 0x40, 0xce, 0x93, 0x04, 0x67, 0x99, 0x4f, 0x23, 0xdd, 0x75, 0xab, 0xdf, - 0x2a, 0xbf, 0x1c, 0x46, 0xe8, 0x33, 0x58, 0xc3, 0x49, 0xc2, 0x43, 0x2c, 0x49, 0xe4, 0xe3, 0x94, - 0x17, 0x4c, 0xb6, 0x17, 0x34, 0xb3, 0xab, 0xda, 0xfe, 0xfd, 0xd5, 0xc6, 0xdb, 0x31, 0x95, 0xc7, - 0x45, 0xe0, 0x86, 0x3c, 0x2d, 0xcf, 0xb6, 0x7c, 0x3c, 0x12, 0xd1, 0x37, 0x9e, 0x1c, 0x65, 0x44, - 0xb8, 0x87, 0x4c, 0xf6, 0x57, 0x6b, 0x9e, 0xc7, 0x9a, 0x06, 0x1d, 0xc1, 0x4a, 0xc0, 0x59, 0x44, - 0x59, 0xec, 0x87, 0x45, 0x3e, 0x20, 0xed, 0x86, 0x96, 0x6c, 0x73, 0x92, 0x64, 0x5d, 0x53, 0x70, - 0xa0, 0xf0, 0xa5, 0x70, 0xcb, 0xc1, 0xd8, 0x37, 0x74, 0x00, 0x20, 0x24, 0xce, 0xa5, 0xaf, 0x9c, - 0xd0, 0x5e, 0xd4, 0x8c, 0xb6, 0x6b, 0x6c, 0xe2, 0x56, 0x36, 0x71, 0x3f, 0xa9, 0x6c, 0xd2, 0xbd, - 0xa6, 0x38, 0x9e, 0xfd, 0xb1, 0x61, 0xf5, 0x5b, 0xba, 0x4e, 0x65, 0xd0, 0x13, 0x58, 0xcd, 0x72, - 0xe2, 0x27, 0xb8, 0x60, 0xe1, 0xb1, 0x61, 0x6a, 0x5e, 0x81, 0x69, 0x25, 0xcb, 0xc9, 0x13, 0x5d, - 0xab, 0xd9, 0x28, 0xdc, 0xa1, 0x2c, 0x24, 0x4c, 0xd2, 0x01, 0xf1, 0xb3, 0x04, 0xb3, 0xca, 0x22, - 0x4b, 0x9a, 0xd3, 0x9b, 0xb4, 0xdf, 0xc3, 0xaa, 0x50, 0x9d, 0xed, 0x05, 0xbf, 0xdc, 0xa2, 0xff, - 0x4c, 0xed, 0x83, 0x72, 0x8e, 0x39, 0x58, 0x67, 0x1b, 0xee, 0x5c, 0x70, 0x46, 0xe5, 0x19, 0xb4, - 0x0e, 0x4b, 0xba, 0x0b, 0x1a, 0x19, 0x8f, 0xf4, 0x9b, 0x2a, 0x3c, 0x8c, 0x9c, 0x1f, 0xe6, 0xa1, - 0xd9, 0x13, 0x71, 0xb7, 0x18, 0x29, 0x17, 0x05, 0xc5, 0x68, 0x16, 0x17, 0x69, 0xd8, 0x38, 0xe7, - 0xfc, 0x38, 0x27, 0x7a, 0x1f, 0x9a, 0xff, 0xc9, 0x35, 0x65, 0x35, 0xfa, 0x12, 0x6e, 0x91, 0x61, - 0x46, 0x42, 0x65, 0x43, 0x5e, 0xc8, 0xca, 0x8a, 0x8d, 0x7f, 0x45, 0x7a, 0xb3, 0xa2, 0xfa, 0xa8, - 0x90, 0xc6, 0x8c, 0xa5, 0x72, 0x7a, 0x33, 0xce, 0x1a, 0xdc, 0x30, 0x32, 0xd4, 0xd7, 0xec, 0xc7, - 0x79, 0x58, 0xea, 0x89, 0xf8, 0x88, 0x24, 0x09, 0xda, 0x86, 0xa6, 0x20, 0x49, 0x32, 0x83, 0x36, - 0x25, 0xee, 0xff, 0x2f, 0xce, 0x75, 0x25, 0x4e, 0xb9, 0x1b, 0xe7, 0xa6, 0x9e, 0x98, 0x4a, 0x8a, - 0x5a, 0x1e, 0x02, 0xd7, 0x94, 0xd5, 0x12, 0x4c, 0x53, 0xb4, 0x0b, 0x4b, 0xa1, 0x7a, 0x99, 0x41, - 0x9f, 0x0a, 0x78, 0xa9, 0x40, 0xfb, 0xcb, 0x6a, 0xe1, 0x0a, 0xe6, 0x20, 0x58, 0xab, 0x96, 0xa9, - 0x96, 0xde, 0xfd, 0x6b, 0x01, 0x16, 0x7a, 0x22, 0x46, 0x19, 0x2c, 0x5f, 0x18, 0xe2, 0x0f, 0x27, - 0xdd, 0xaa, 0x37, 0xa6, 0xa9, 0xbd, 0x77, 0x05, 0x70, 0x7d, 0x8d, 0xbe, 0x06, 0x18, 0x1b, 0xbb, - 0xef, 0x4c, 0xa1, 0x38, 0x87, 0xda, 0x3b, 0x33, 0x43, 0xeb, 0xb5, 0x9e, 0xc2, 0x82, 0xba, 0x95, - 0xce, 0x94, 0xca, 0x6e, 0x31, 0xb2, 0xb7, 0xa6, 0x63, 0x6a, 0xda, 0x4f, 0xa1, 0xa1, 0x2d, 0x7d, - 0x7f, 0x4a, 0x8d, 0x02, 0xd9, 0x0f, 0x67, 0x00, 0xd5, 0xcc, 0x5f, 0xc0, 0xa2, 0xb1, 0xc3, 0x83, - 0x69, 0x9b, 0x55, 0x28, 0xfb, 0xdd, 0x59, 0x50, 0x15, 0xb9, 0xbd, 0xf8, 0xdd, 0xeb, 0xe7, 0x5b, - 0x56, 0xf7, 0xc3, 0x17, 0xa7, 0x1d, 0xeb, 0xe5, 0x69, 0xc7, 0xfa, 0xf3, 0xb4, 0x63, 0x3d, 0x3b, - 0xeb, 0xcc, 0xbd, 0x3c, 0xeb, 0xcc, 0xfd, 0x76, 0xd6, 0x99, 0xfb, 0x7c, 0x7b, 0xcc, 0xea, 0x97, - 0xfc, 0x47, 0x0c, 0xf6, 0xbc, 0xa1, 0xf9, 0xaf, 0x51, 0xc6, 0x0f, 0x9a, 0x7a, 0xa0, 0xef, 0xfd, - 0x1d, 0x00, 0x00, 0xff, 0xff, 0x49, 0x74, 0x51, 0x56, 0x02, 0x09, 0x00, 0x00, + // 862 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0xcf, 0x6f, 0xdc, 0x44, + 0x14, 0x8e, 0x93, 0xcd, 0xa6, 0xfb, 0x9a, 0x74, 0xd3, 0xa1, 0x55, 0xb6, 0x96, 0xd8, 0x54, 0x6e, + 0x85, 0x42, 0x4a, 0xed, 0xfc, 0x90, 0x38, 0xe4, 0xd6, 0x8d, 0x04, 0x5a, 0xd4, 0x95, 0xd0, 0x86, + 0x22, 0x28, 0x07, 0x6b, 0xd6, 0x1e, 0x9c, 0x01, 0x7b, 0xc6, 0xf2, 0x8c, 0x37, 0xbb, 0x9c, 0x10, + 0x12, 0xf7, 0x1e, 0x39, 0xf3, 0x17, 0xf4, 0xc0, 0x1f, 0xd1, 0x63, 0xc5, 0x09, 0x71, 0x28, 0x28, + 0x39, 0xf4, 0x5f, 0xe0, 0x82, 0x84, 0x66, 0xc6, 0x76, 0x36, 0x45, 0xd9, 0xdd, 0x12, 0x71, 0xb2, + 0x9f, 0xdf, 0xf7, 0xbe, 0x79, 0xf3, 0xcd, 0x37, 0x4f, 0x86, 0x7b, 0xe1, 0x38, 0x21, 0x4c, 0x50, + 0xce, 0x46, 0xe3, 0xef, 0xbc, 0x2a, 0xf0, 0x68, 0xc6, 0x3d, 0x39, 0x72, 0xd3, 0x8c, 0x4b, 0x8e, + 0xec, 0x49, 0x90, 0x5b, 0x05, 0x2e, 0xcd, 0xb8, 0x7d, 0x2b, 0xe2, 0x11, 0xd7, 0x30, 0x4f, 0xbd, + 0x99, 0x0a, 0xfb, 0x4e, 0xc0, 0x45, 0xc2, 0x85, 0x6f, 0x12, 0x26, 0x28, 0x52, 0x1b, 0x26, 0xf2, + 0x12, 0x11, 0x79, 0xc3, 0x5d, 0xf5, 0x28, 0x12, 0xf7, 0xa7, 0xb4, 0x42, 0xb3, 0x92, 0x79, 0x33, + 0xe2, 0x3c, 0x8a, 0x89, 0xa7, 0xa3, 0x41, 0xfe, 0xb5, 0x27, 0x69, 0x42, 0x84, 0xc4, 0x49, 0x5a, + 0x00, 0xda, 0x05, 0xff, 0x00, 0x0b, 0xe2, 0x0d, 0x77, 0x07, 0x44, 0xe2, 0x5d, 0x2f, 0xe0, 0x94, + 0x99, 0xbc, 0xf3, 0xb3, 0x05, 0xcd, 0x9e, 0x88, 0x9e, 0xa4, 0x21, 0x96, 0xe4, 0x53, 0x9c, 0xe1, + 0x44, 0xa0, 0x0f, 0xa1, 0x81, 0x73, 0x79, 0xcc, 0x33, 0x2a, 0xc7, 0x2d, 0xeb, 0xae, 0xb5, 0xd5, + 0xe8, 0xb4, 0x7e, 0xfd, 0xe5, 0xe1, 0xad, 0xa2, 0xf1, 0x47, 0x61, 0x98, 0x11, 0x21, 0x8e, 0x64, + 0x46, 0x59, 0xd4, 0x3f, 0x87, 0xa2, 0x8f, 0x01, 0x18, 0x39, 0xf1, 0x53, 0xcd, 0xd2, 0x5a, 0xbc, + 0x6b, 0x6d, 0x5d, 0xdf, 0x73, 0xdc, 0xcb, 0xd5, 0x72, 0xcd, 0x7a, 0x9d, 0xda, 0x8b, 0x57, 0x9b, + 0x0b, 0xfd, 0x06, 0x23, 0x27, 0xe6, 0xc3, 0xc1, 0x8d, 0x1f, 0x5e, 0x3f, 0xdf, 0x3e, 0x27, 0x76, + 0xee, 0xc0, 0xc6, 0x1b, 0x3d, 0xf6, 0x89, 0x48, 0x39, 0x13, 0xc4, 0xf9, 0xa9, 0x06, 0x6b, 0x3d, + 0x11, 0x1d, 0x66, 0x44, 0xe5, 0x62, 0xcc, 0x90, 0x0b, 0xcb, 0xfc, 0x84, 0x91, 0x6c, 0x66, 0xe7, + 0x06, 0x86, 0xde, 0x05, 0xc8, 0x78, 0x1c, 0xe3, 0x34, 0xf5, 0x69, 0xa8, 0xbb, 0x6e, 0xf4, 0x1b, + 0xc5, 0x97, 0x6e, 0x88, 0xbe, 0x84, 0x75, 0x1c, 0xc7, 0x3c, 0xc0, 0x92, 0x84, 0x3e, 0x4e, 0x78, + 0xce, 0x64, 0x6b, 0x49, 0x33, 0xbb, 0xaa, 0xed, 0xdf, 0x5f, 0x6d, 0xbe, 0x17, 0x51, 0x79, 0x9c, + 0x0f, 0xdc, 0x80, 0x27, 0xc5, 0xd9, 0x16, 0x8f, 0x87, 0x22, 0xfc, 0xd6, 0x93, 0xe3, 0x94, 0x08, + 0xb7, 0xcb, 0x64, 0xbf, 0x59, 0xf1, 0x3c, 0xd2, 0x34, 0xe8, 0x08, 0xd6, 0x06, 0x9c, 0x85, 0x94, + 0x45, 0x7e, 0x90, 0x67, 0x43, 0xd2, 0xaa, 0x69, 0xc9, 0xb6, 0xa6, 0x49, 0xd6, 0x31, 0x05, 0x87, + 0x0a, 0x5f, 0x08, 0xb7, 0x3a, 0x98, 0xf8, 0x86, 0x0e, 0x01, 0x84, 0xc4, 0x99, 0xf4, 0x95, 0x13, + 0x5a, 0xcb, 0x9a, 0xd1, 0x76, 0x8d, 0x4d, 0xdc, 0xd2, 0x26, 0xee, 0x67, 0xa5, 0x4d, 0x3a, 0xd7, + 0x14, 0xc7, 0xb3, 0x3f, 0x36, 0xad, 0x7e, 0x43, 0xd7, 0xa9, 0x0c, 0x7a, 0x0c, 0xcd, 0x34, 0x23, + 0x7e, 0x8c, 0x73, 0x16, 0x1c, 0x1b, 0xa6, 0xfa, 0x5b, 0x30, 0xad, 0xa5, 0x19, 0x79, 0xac, 0x6b, + 0x35, 0x1b, 0x85, 0xdb, 0x94, 0x05, 0x84, 0x49, 0x3a, 0x24, 0x7e, 0x1a, 0x63, 0x56, 0x5a, 0x64, + 0x45, 0x73, 0x7a, 0xd3, 0xf6, 0xdb, 0x2d, 0x0b, 0xd5, 0xd9, 0x5e, 0xf0, 0xcb, 0x3b, 0xf4, 0xdf, + 0xa9, 0x03, 0x50, 0xce, 0x31, 0x07, 0xeb, 0xec, 0xc0, 0xed, 0x0b, 0xce, 0x28, 0x3d, 0x83, 0x36, + 0x60, 0x45, 0x77, 0x41, 0x43, 0xe3, 0x91, 0x7e, 0x5d, 0x85, 0xdd, 0xd0, 0xf9, 0xdb, 0x82, 0x7a, + 0x4f, 0x44, 0x9d, 0x7c, 0xac, 0x5c, 0x34, 0xc8, 0xc7, 0xf3, 0xb8, 0x48, 0xc3, 0x26, 0x39, 0x17, + 0x27, 0x39, 0xd1, 0x47, 0x50, 0xbf, 0x92, 0x6b, 0x8a, 0x6a, 0xf4, 0x39, 0x34, 0x13, 0x3c, 0xf2, + 0x03, 0x2e, 0x64, 0x69, 0xc3, 0xda, 0x7f, 0x22, 0x5c, 0x4b, 0xf0, 0xe8, 0x90, 0x0b, 0x69, 0x4c, + 0x58, 0x28, 0xa6, 0x37, 0xe1, 0xac, 0xc3, 0x0d, 0xb3, 0xfd, 0xea, 0x7a, 0xfd, 0xb8, 0x08, 0x2b, + 0x3d, 0x11, 0x1d, 0x91, 0x38, 0x46, 0x3b, 0x50, 0x17, 0x24, 0x8e, 0xe7, 0xd0, 0xa4, 0xc0, 0xfd, + 0xff, 0xa2, 0x3c, 0x85, 0x9b, 0x09, 0x65, 0x3e, 0x65, 0x01, 0x4f, 0xc8, 0xd5, 0x64, 0x69, 0x26, + 0x94, 0x75, 0x35, 0x4f, 0x21, 0xcc, 0x75, 0x25, 0x4c, 0xb1, 0x13, 0xe7, 0xa6, 0x9e, 0x92, 0x4a, + 0x86, 0x4a, 0x1a, 0x02, 0xd7, 0x94, 0xbd, 0x62, 0x4c, 0x13, 0xb4, 0x07, 0x2b, 0x81, 0x7a, 0x99, + 0x43, 0x9b, 0x12, 0x78, 0xa9, 0x38, 0x07, 0xab, 0x6a, 0xe1, 0x12, 0xe6, 0x20, 0x58, 0x2f, 0x97, + 0x29, 0x97, 0xde, 0xfb, 0x6b, 0x09, 0x96, 0x7a, 0x22, 0x42, 0x29, 0xac, 0x5e, 0x18, 0xdc, 0x0f, + 0xa6, 0xdd, 0xa4, 0x37, 0x26, 0xa8, 0xbd, 0xff, 0x16, 0xe0, 0xea, 0xea, 0x7c, 0x03, 0x30, 0x31, + 0x6a, 0xdf, 0x9f, 0x41, 0x71, 0x0e, 0xb5, 0x77, 0xe7, 0x86, 0x56, 0x6b, 0x3d, 0x81, 0x25, 0x75, + 0x13, 0x9d, 0x19, 0x95, 0x9d, 0x7c, 0x6c, 0x6f, 0xcf, 0xc6, 0x54, 0xb4, 0x5f, 0x40, 0x4d, 0xdb, + 0xf9, 0xde, 0x8c, 0x1a, 0x05, 0xb2, 0x1f, 0xcc, 0x01, 0xaa, 0x98, 0xbf, 0x82, 0x65, 0x63, 0x87, + 0xfb, 0xb3, 0x36, 0xab, 0x50, 0xf6, 0x07, 0xf3, 0xa0, 0x4a, 0x72, 0x7b, 0xf9, 0xfb, 0xd7, 0xcf, + 0xb7, 0xad, 0xce, 0x27, 0x2f, 0x4e, 0xdb, 0xd6, 0xcb, 0xd3, 0xb6, 0xf5, 0xe7, 0x69, 0xdb, 0x7a, + 0x76, 0xd6, 0x5e, 0x78, 0x79, 0xd6, 0x5e, 0xf8, 0xed, 0xac, 0xbd, 0xf0, 0x74, 0x67, 0xc2, 0xe8, + 0x97, 0xfc, 0x3b, 0x0c, 0xf7, 0xbd, 0x91, 0xf9, 0x97, 0x51, 0xb6, 0x1f, 0xd4, 0xf5, 0x10, 0xdf, + 0xff, 0x27, 0x00, 0x00, 0xff, 0xff, 0x99, 0x7f, 0x1d, 0x56, 0xf6, 0x08, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1047,9 +1048,9 @@ func (m *MsgBuy) MarshalToSizedBuffer(dAtA []byte) (int, error) { var l int _ = l { - size := m.ExpectedOutAmount.Size() + size := m.MaxCostAmount.Size() i -= size - if _, err := m.ExpectedOutAmount.MarshalTo(dAtA[i:]); err != nil { + if _, err := m.MaxCostAmount.MarshalTo(dAtA[i:]); err != nil { return 0, err } i = encodeVarintTx(dAtA, i, uint64(size)) @@ -1127,9 +1128,9 @@ func (m *MsgSell) MarshalToSizedBuffer(dAtA []byte) (int, error) { var l int _ = l { - size := m.ExpectedOutAmount.Size() + size := m.MinIncomeAmount.Size() i -= size - if _, err := m.ExpectedOutAmount.MarshalTo(dAtA[i:]); err != nil { + if _, err := m.MinIncomeAmount.MarshalTo(dAtA[i:]); err != nil { return 0, err } i = encodeVarintTx(dAtA, i, uint64(size)) @@ -1337,7 +1338,7 @@ func (m *MsgBuy) Size() (n int) { } l = m.Amount.Size() n += 1 + l + sovTx(uint64(l)) - l = m.ExpectedOutAmount.Size() + l = m.MaxCostAmount.Size() n += 1 + l + sovTx(uint64(l)) return n } @@ -1367,7 +1368,7 @@ func (m *MsgSell) Size() (n int) { } l = m.Amount.Size() n += 1 + l + sovTx(uint64(l)) - l = m.ExpectedOutAmount.Size() + l = m.MinIncomeAmount.Size() n += 1 + l + sovTx(uint64(l)) return n } @@ -2069,7 +2070,7 @@ func (m *MsgBuy) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ExpectedOutAmount", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field MaxCostAmount", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -2097,7 +2098,7 @@ func (m *MsgBuy) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.ExpectedOutAmount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.MaxCostAmount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -2301,7 +2302,7 @@ func (m *MsgSell) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ExpectedOutAmount", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field MinIncomeAmount", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -2329,7 +2330,7 @@ func (m *MsgSell) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.ExpectedOutAmount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.MinIncomeAmount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex