Skip to content

Commit ff7e9b8

Browse files
committed
pump stream 1
1 parent 5da6a33 commit ff7e9b8

File tree

5 files changed

+76
-79
lines changed

5 files changed

+76
-79
lines changed

x/iro/keeper/msg_server.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ func (m msgServer) BuyExactSpend(ctx context.Context, req *types.MsgBuyExactSpen
5656
return nil, err
5757
}
5858

59-
err = m.Keeper.BuyExactSpend(sdk.UnwrapSDKContext(ctx), req.PlanId, buyer, req.Spend, req.MinOutTokensAmount)
59+
_, err = m.Keeper.BuyExactSpend(sdk.UnwrapSDKContext(ctx), req.PlanId, buyer, req.Spend, req.MinOutTokensAmount)
6060
if err != nil {
6161
return nil, err
6262
}

x/iro/keeper/trade.go

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -115,53 +115,58 @@ func (k Keeper) Buy(ctx sdk.Context, planId string, buyer sdk.AccAddress, amount
115115
}
116116

117117
// BuyExactSpend uses exact amount of liquidity to buy tokens on the curve
118-
func (k Keeper) BuyExactSpend(ctx sdk.Context, planId string, buyer sdk.AccAddress, amountToSpend, minTokensAmt math.Int) error {
118+
func (k Keeper) BuyExactSpend(
119+
ctx sdk.Context,
120+
planId string,
121+
buyer sdk.AccAddress,
122+
amountToSpend, minTokensAmt math.Int,
123+
) (tokensOutAmt math.Int, err error) {
119124
plan, err := k.GetTradeableIRO(ctx, planId, buyer)
120125
if err != nil {
121-
return err
126+
return math.ZeroInt(), err
122127
}
123128

124129
// deduct taker fee from the amount to spend
125130
toSpendMinusTakerFeeAmt, takerFeeAmt, err := k.ApplyTakerFee(amountToSpend, k.GetParams(ctx).TakerFee, false)
126131
if err != nil {
127-
return err
132+
return math.ZeroInt(), err
128133
}
129134

130135
// calculate the amount of tokens possible to buy with the amount to spend
131-
tokensOutAmt, err := plan.BondingCurve.TokensForExactInAmount(plan.SoldAmt, toSpendMinusTakerFeeAmt)
136+
tokensOutAmt, err = plan.BondingCurve.TokensForExactInAmount(plan.SoldAmt, toSpendMinusTakerFeeAmt)
132137
if err != nil {
133-
return err
138+
return math.ZeroInt(), err
134139
}
135140

136141
// Validate expected out amount
137142
if tokensOutAmt.LT(minTokensAmt) {
138-
return errorsmod.Wrapf(types.ErrInvalidMinCost, "minTokens: %s, tokens: %s, fee: %s", minTokensAmt.String(), tokensOutAmt.String(), takerFeeAmt.String())
143+
return math.ZeroInt(), errorsmod.Wrapf(types.ErrInvalidMinCost, "minTokens: %s, tokens: %s, fee: %s", minTokensAmt.String(), tokensOutAmt.String(), takerFeeAmt.String())
139144
}
140145

141146
// validate the IRO have enough tokens to sell
142147
if plan.SoldAmt.Add(tokensOutAmt).GT(plan.MaxAmountToSell) {
143-
return types.ErrInsufficientTokens
148+
return math.ZeroInt(), types.ErrInsufficientTokens
144149
}
145150

146151
// Charge taker fee
147152
takerFee := sdk.NewCoin(plan.LiquidityDenom, takerFeeAmt)
148153
owner := k.rk.MustGetRollappOwner(ctx, plan.RollappId)
149154
err = k.chargeTakerFee(ctx, takerFee, buyer, &owner)
150155
if err != nil {
151-
return err
156+
return math.ZeroInt(), err
152157
}
153158

154159
// Send liquidity token from buyer to the plan. The liquidity token sent directly to the plan's module account
155160
cost := sdk.NewCoin(plan.LiquidityDenom, toSpendMinusTakerFeeAmt)
156161
err = k.BK.SendCoins(ctx, buyer, plan.GetAddress(), sdk.NewCoins(cost))
157162
if err != nil {
158-
return err
163+
return math.ZeroInt(), err
159164
}
160165

161166
// send allocated tokens from the plan to the buyer
162167
err = k.BK.SendCoinsFromModuleToAccount(ctx, types.ModuleName, buyer, sdk.NewCoins(sdk.NewCoin(plan.TotalAllocation.Denom, tokensOutAmt)))
163168
if err != nil {
164-
return err
169+
return math.ZeroInt(), err
165170
}
166171

167172
// Update plan
@@ -179,10 +184,10 @@ func (k Keeper) BuyExactSpend(ctx sdk.Context, planId string, buyer sdk.AccAddre
179184
ClosingPrice: plan.SpotPrice(),
180185
})
181186
if err != nil {
182-
return err
187+
return math.ZeroInt(), err
183188
}
184189

185-
return nil
190+
return tokensOutAmt, nil
186191
}
187192

188193
// Sell sells allocation with price according to the price curve

x/streamer/keeper/keeper.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ type Keeper struct {
3131
iroKeeper types.IROKeeper
3232
poolManagerKeeper types.PoolManagerKeeper
3333
rollappKeeper types.RollappKeeper
34+
txFeesKeeper types.TxFeesKeeper
3435

3536
authority string
3637

@@ -51,6 +52,7 @@ func NewKeeper(
5152
iroKeeper types.IROKeeper,
5253
poolManagerKeeper types.PoolManagerKeeper,
5354
rollappKeeper types.RollappKeeper,
55+
txFeesKeeper types.TxFeesKeeper,
5456
authority string,
5557
) *Keeper {
5658
sb := collections.NewSchemaBuilder(collcompat.NewKVStoreService(storeKey))
@@ -67,6 +69,7 @@ func NewKeeper(
6769
iroKeeper: iroKeeper,
6870
poolManagerKeeper: poolManagerKeeper,
6971
rollappKeeper: rollappKeeper,
72+
txFeesKeeper: txFeesKeeper,
7073
authority: authority,
7174
epochPointers: collections.NewMap(
7275
sb,

x/streamer/keeper/pump_stream.go

Lines changed: 48 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -13,29 +13,6 @@ import (
1313
poolmanagertypes "github.com/osmosis-labs/osmosis/v15/x/poolmanager/types"
1414
)
1515

16-
// ShouldExecutePump decides if the pump should happen in this block based on stream's pump params.
17-
func (k Keeper) ShouldExecutePump(ctx sdk.Context, stream types.Stream) (bool, error) {
18-
if stream.PumpParams == nil {
19-
return false, nil
20-
}
21-
22-
if stream.PumpParams.EpochBudgetLeft.IsZero() {
23-
return false, nil
24-
}
25-
26-
epochBlocks, err := k.EpochBlocks(ctx, stream.DistrEpochIdentifier)
27-
if err != nil {
28-
return false, fmt.Errorf("failed to get epoch blocks: %w", err)
29-
}
30-
31-
pumpAmt, err := ShouldPump(ctx, stream.PumpParams.EpochBudget, stream.PumpParams.EpochBudgetLeft, stream.PumpParams.NumPumps, epochBlocks)
32-
if err != nil {
33-
return false, fmt.Errorf("failed to calculate pump amount: %w", err)
34-
}
35-
36-
return !pumpAmt.IsZero(), nil
37-
}
38-
3916
// ShouldPump decides if the pump should happen in this block. It uses block
4017
// hash and block time as entropy.
4118
//
@@ -116,63 +93,73 @@ func (k Keeper) ExecutePump(
11693
ctx sdk.Context,
11794
pumpAmt math.Int,
11895
rollappID string,
119-
) error {
96+
) (tokenOut sdk.Coin, err error) {
12097
rollapp, found := k.rollappKeeper.GetRollapp(ctx, rollappID)
12198
if !found {
122-
return fmt.Errorf("rollapp not found: %s", rollappID)
99+
return sdk.Coin{}, fmt.Errorf("rollapp not found: %s", rollappID)
123100
}
124101

125102
plan, found := k.iroKeeper.GetPlanByRollapp(ctx, rollapp.RollappId)
126103
if !found {
127-
return fmt.Errorf("IRO plan not found for rollapp: %s", rollappID)
104+
return sdk.Coin{}, fmt.Errorf("IRO plan not found for rollapp: %s", rollappID)
128105
}
129106

130-
address := k.ak.GetModuleAddress(types.ModuleName)
131-
// TODO: get base denom
132-
baseDenom := "adym" // Base denom for budget
107+
// Always use base denom for budget
108+
baseDenom, err := k.txFeesKeeper.GetBaseDenom(ctx)
109+
if err != nil {
110+
return sdk.Coin{}, fmt.Errorf("get base denom: %w", err)
111+
}
133112

134-
return osmoutils.ApplyFuncIfNoError(ctx, func(ctx sdk.Context) error {
135-
var targetDenom string
136-
if plan.IsSettled() {
137-
targetDenom = plan.SettledDenom
138-
} else {
139-
targetDenom = plan.LiquidityDenom
140-
}
113+
var targetDenom string
114+
if plan.IsSettled() {
115+
targetDenom = plan.SettledDenom
116+
} else {
117+
targetDenom = plan.LiquidityDenom
118+
}
141119

142-
// Get FeeToken for target denom to find routing
143-
feeToken, err := k.getFeeTokenForDenom(ctx, targetDenom)
144-
if err != nil {
145-
return fmt.Errorf("get fee token for denom %s: %w", targetDenom, err)
146-
}
120+
// Get FeeToken for target denom to find routing to the base denom.
121+
// Every token must have a route to the base denom.
122+
feeToken, err := k.txFeesKeeper.GetFeeToken(ctx, targetDenom)
123+
if err != nil {
124+
return sdk.Coin{}, fmt.Errorf("get fee token for denom %s: %w", targetDenom, err)
125+
}
147126

148-
tokenIn := sdk.NewCoin(baseDenom, pumpAmt)
127+
buyer := k.ak.GetModuleAddress(types.ModuleName)
128+
var tokenOutAmt math.Int
149129

150-
targetAmount, err := k.poolManagerKeeper.RouteExactAmountIn(
130+
err = osmoutils.ApplyFuncIfNoError(ctx, func(ctx sdk.Context) error {
131+
// Buy:
132+
// - RA tokens if IRO is over
133+
// - Liquidity tokens if IRO is in progress
134+
tokenOutAmt, err := k.poolManagerKeeper.RouteExactAmountIn(
151135
ctx,
152-
address,
153-
feeToken.Route, // Use route from FeeToken
154-
tokenIn,
155-
math.ZeroInt(), // tokenOutMinAmount = 0 (ignore slippage for now)
136+
buyer,
137+
feeToken.Route,
138+
sdk.NewCoin(baseDenom, pumpAmt), // token in
139+
math.ZeroInt(), // no slippage)
156140
)
157141
if err != nil {
158142
return fmt.Errorf("route exact amount in: target denom: %s, error: %w", targetDenom, err)
159143
}
160144

161145
if !plan.IsSettled() {
162-
err = k.iroKeeper.BuyExactSpend(
146+
// If IRO is in progress, use liquidity tokens to buy IRO tokens
147+
tokenOutAmt, err = k.iroKeeper.BuyExactSpend(
163148
ctx,
164149
fmt.Sprintf("%d", plan.Id),
165-
address,
166-
targetAmount, // amountToSpend
167-
math.ZeroInt(), // minTokensAmt = 0
150+
buyer,
151+
tokenOutAmt, // amountToSpend
152+
math.ZeroInt(), // no slippage
168153
)
169154
if err != nil {
170-
return fmt.Errorf("buy from IRO: %w", err)
155+
return fmt.Errorf("buy from IRO %d: %w", plan.Id, err)
171156
}
172157
}
173158

174159
return nil
175160
})
161+
162+
return sdk.NewCoin(targetDenom, tokenOutAmt), err
176163
}
177164

178165
// getFeeTokenForDenom gets the FeeToken configuration for a given denom
@@ -210,33 +197,29 @@ func (k Keeper) DistributePumpStreams(ctx sdk.Context, pumpStreams []types.Strea
210197
}
211198

212199
// Use ShouldPump directly to determine pump amount
213-
pumpAmt, err := ShouldPump(ctx, stream.PumpParams.EpochBudget, stream.PumpParams.EpochBudgetLeft, stream.PumpParams.NumPumps, epochBlocks)
200+
pumpAmt, err := ShouldPump(
201+
ctx,
202+
stream.PumpParams.EpochBudget,
203+
stream.PumpParams.EpochBudgetLeft,
204+
stream.PumpParams.NumPumps,
205+
epochBlocks,
206+
)
214207
if err != nil {
215208
return fmt.Errorf("failed to calculate pump amount: %w", err)
216209
}
217210

218211
if pumpAmt.IsZero() {
212+
// Shouldn't pump on this iteration
219213
continue
220214
}
221215

222216
// Get top rollapps from the stream's distribution
223217
rollapps := k.TopRollapps(ctx, stream.DistributeTo.Records, stream.PumpParams.NumTopRollapps)
224218

225-
// Calculate total weight for proportional distribution
226-
totalWeight := math.ZeroInt()
227-
for _, rollapp := range rollapps {
228-
totalWeight = totalWeight.Add(rollapp.Weight)
229-
}
230-
231-
if totalWeight.IsZero() {
232-
k.Logger(ctx).Info("no valid rollapps found for pump stream", "streamID", stream.Id)
233-
continue
234-
}
235-
236219
// Distribute pump amount proportionally to each rollapp
237220
for _, rollapp := range rollapps {
238221
// Calculate proportional pump amount based on rollapp weight
239-
pumpAmtRA := pumpAmt.Mul(rollapp.Weight).Quo(totalWeight)
222+
pumpAmtRA := pumpAmt.Mul(rollapp.Weight).Quo(stream.DistributeTo.TotalWeight)
240223

241224
if pumpAmtRA.IsZero() {
242225
continue

x/streamer/types/expected_keepers.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
1010
epochstypes "github.com/osmosis-labs/osmosis/v15/x/epochs/types"
1111
poolmanagertypes "github.com/osmosis-labs/osmosis/v15/x/poolmanager/types"
12+
txfeestypes "github.com/osmosis-labs/osmosis/v15/x/txfees/types"
1213

1314
incentivestypes "github.com/dymensionxyz/dymension/v3/x/incentives/types"
1415
irotypes "github.com/dymensionxyz/dymension/v3/x/iro/types"
@@ -57,7 +58,7 @@ type MintParamsGetter interface {
5758

5859
type IROKeeper interface {
5960
GetPlanByRollapp(ctx sdk.Context, rollappId string) (irotypes.Plan, bool)
60-
BuyExactSpend(ctx sdk.Context, planId string, buyer sdk.AccAddress, amountToSpend, minTokensAmt math.Int) error
61+
BuyExactSpend(ctx sdk.Context, planId string, buyer sdk.AccAddress, amountToSpend, minTokensAmt math.Int) (math.Int, error)
6162
}
6263

6364
type PoolManagerKeeper interface {
@@ -73,3 +74,8 @@ type PoolManagerKeeper interface {
7374
type RollappKeeper interface {
7475
GetRollapp(ctx sdk.Context, rollappId string) (rollapptypes.Rollapp, bool)
7576
}
77+
78+
type TxFeesKeeper interface {
79+
GetFeeToken(ctx sdk.Context, denom string) (txfeestypes.FeeToken, error)
80+
GetBaseDenom(ctx sdk.Context) (string, error)
81+
}

0 commit comments

Comments
 (0)