Skip to content

Commit

Permalink
[CL Hooks]: Implement CL hook message types and high level hook funct…
Browse files Browse the repository at this point in the history
…ions (osmosis-labs#6845)

* implement hook messages and calls

* add comments and clean up helpers

* osmoutils go mod

* go mod osmoutils
  • Loading branch information
AlpinYukseloglu authored Nov 13, 2023
1 parent 04807a0 commit 8c26c80
Show file tree
Hide file tree
Showing 6 changed files with 303 additions and 20 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ require (
github.com/ory/dockertest/v3 v3.10.0
github.com/osmosis-labs/go-mutesting v0.0.0-20221208041716-b43bcd97b3b3
github.com/osmosis-labs/osmosis/osmomath v0.0.7-0.20231108202153-af031b1367bb
github.com/osmosis-labs/osmosis/osmoutils v0.0.7-0.20231110043608-da030c5b18ac
github.com/osmosis-labs/osmosis/osmoutils v0.0.7-0.20231113053702-9d3cce854a9d
github.com/osmosis-labs/osmosis/x/epochs v0.0.3-0.20231108202153-af031b1367bb
github.com/osmosis-labs/osmosis/x/ibc-hooks v0.0.9-0.20231108202153-af031b1367bb
github.com/pkg/errors v0.9.1
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1460,6 +1460,8 @@ github.com/osmosis-labs/osmosis/osmomath v0.0.7-0.20231108202153-af031b1367bb h1
github.com/osmosis-labs/osmosis/osmomath v0.0.7-0.20231108202153-af031b1367bb/go.mod h1:I8CSvdOyPJREATq1Kb4mFPiDVrl2jxCRd4W3NVQFom8=
github.com/osmosis-labs/osmosis/osmoutils v0.0.7-0.20231110043608-da030c5b18ac h1:60A8/hLeNPpEJ4QPoJbpN0BgJEjMzcAy+0lByxGIlaE=
github.com/osmosis-labs/osmosis/osmoutils v0.0.7-0.20231110043608-da030c5b18ac/go.mod h1:5vLzE4XFr/qa5bXq6zSFncM3jUwTMOW9hMjVRSlTQAc=
github.com/osmosis-labs/osmosis/osmoutils v0.0.7-0.20231113053702-9d3cce854a9d h1:HU/Ti1vae94c2u+AGqCKnVM2YOboewjTfxbMhu1T2rY=
github.com/osmosis-labs/osmosis/osmoutils v0.0.7-0.20231113053702-9d3cce854a9d/go.mod h1:5vLzE4XFr/qa5bXq6zSFncM3jUwTMOW9hMjVRSlTQAc=
github.com/osmosis-labs/osmosis/x/epochs v0.0.3-0.20231108202153-af031b1367bb h1:Gz4FoT0QgrqbYUt+fj+pl7kpcmv/Jd4VAKWOq3Bjpow=
github.com/osmosis-labs/osmosis/x/epochs v0.0.3-0.20231108202153-af031b1367bb/go.mod h1:mno+X8PKNJZ+zKX+nG0R2Z0tEc+IM5RSvIRWKjhY+UA=
github.com/osmosis-labs/osmosis/x/ibc-hooks v0.0.9-0.20231108202153-af031b1367bb h1:GsepaIGS+uWEZT0K7cQ9hxjIVN5U6x+jzOr/7qNz7cc=
Expand Down
18 changes: 18 additions & 0 deletions osmoutils/coin_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package osmoutils
import (
"fmt"

wasmvmtypes "github.com/CosmWasm/wasmvm/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)

Expand Down Expand Up @@ -126,6 +127,23 @@ func MergeCoinMaps[T comparable](currentEpochExpectedDistributionsOne map[T]sdk.
return newMap
}

// Convert sdk.Coins to wasmvmtypes.Coins
func CWCoinsFromSDKCoins(in sdk.Coins) wasmvmtypes.Coins {
var cwCoins wasmvmtypes.Coins
for _, coin := range in {
cwCoins = append(cwCoins, CWCoinFromSDKCoin(coin))
}
return cwCoins
}

// Convert sdk.Coin to wasmvmtypes.Coin
func CWCoinFromSDKCoin(in sdk.Coin) wasmvmtypes.Coin {
return wasmvmtypes.Coin{
Denom: in.GetDenom(),
Amount: in.Amount.String(),
}
}

func ConvertCoinArrayToCoins(coinArray []sdk.Coin) sdk.Coins {
coins := sdk.Coins{}
for _, coin := range coinArray {
Expand Down
128 changes: 127 additions & 1 deletion x/concentrated-liquidity/pool_hooks.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,139 @@
package concentrated_liquidity

import (
"encoding/json"
"fmt"

"github.com/cosmos/cosmos-sdk/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/osmosis-labs/osmosis/osmomath"
"github.com/osmosis-labs/osmosis/osmoutils"
types "github.com/osmosis-labs/osmosis/v20/x/concentrated-liquidity/types"
)

// nolint: unused
// Helper function to generate before action prefix
func beforeActionPrefix(action string) string {
return fmt.Sprintf("before%s", action)
}

// Helper function to generate after action prefix
func afterActionPrefix(action string) string {
return fmt.Sprintf("after%s", action)
}

// --- Pool Hooks ---

// BeforeCreatePosition is a hook that is called before a position is created.
func (k Keeper) BeforeCreatePosition(ctx sdk.Context, poolId uint64, owner sdk.AccAddress, tokensProvided sdk.Coins, amount0Min osmomath.Int, amount1Min osmomath.Int, lowerTick int64, upperTick int64) error {
// Build and marshal the message to be passed to the contract
msg := types.BeforeCreatePositionMsg{PoolId: poolId, Owner: owner, TokensProvided: osmoutils.CWCoinsFromSDKCoins(tokensProvided), Amount0Min: amount0Min, Amount1Min: amount1Min, LowerTick: lowerTick, UpperTick: upperTick}
msgBz, err := json.Marshal(types.BeforeCreatePositionSudoMsg{BeforeCreatePosition: msg})
if err != nil {
return err
}
return k.callPoolActionListener(ctx, msgBz, poolId, beforeActionPrefix(types.CreatePositionPrefix))
}

// AfterCreatePosition is a hook that is called after a position is created.
func (k Keeper) AfterCreatePosition(ctx sdk.Context, poolId uint64, owner sdk.AccAddress, tokensProvided sdk.Coins, amount0Min osmomath.Int, amount1Min osmomath.Int, lowerTick int64, upperTick int64) error {
// Build and marshal the message to be passed to the contract
msg := types.AfterCreatePositionMsg{PoolId: poolId, Owner: owner, TokensProvided: osmoutils.CWCoinsFromSDKCoins(tokensProvided), Amount0Min: amount0Min, Amount1Min: amount1Min, LowerTick: lowerTick, UpperTick: upperTick}
msgBz, err := json.Marshal(types.AfterCreatePositionSudoMsg{AfterCreatePosition: msg})
if err != nil {
return err
}
return k.callPoolActionListener(ctx, msgBz, poolId, afterActionPrefix(types.CreatePositionPrefix))
}

// BeforeAddToPosition is a hook that is called before liquidity is added to a position.
func (k Keeper) BeforeAddToPosition(ctx sdk.Context, poolId uint64, owner sdk.AccAddress, positionId uint64, amount0Added osmomath.Int, amount1Added osmomath.Int, amount0Min osmomath.Int, amount1Min osmomath.Int) error {
// Build and marshal the message to be passed to the contract
msg := types.BeforeAddToPositionMsg{PoolId: poolId, Owner: owner, PositionId: positionId, Amount0Added: amount0Added, Amount1Added: amount1Added, Amount0Min: amount0Min, Amount1Min: amount1Min}
msgBz, err := json.Marshal(types.BeforeAddToPositionSudoMsg{BeforeAddToPosition: msg})
if err != nil {
return err
}
return k.callPoolActionListener(ctx, msgBz, poolId, beforeActionPrefix(types.AddToPositionPrefix))
}

// AfterAddToPosition is a hook that is called after liquidity is added to a position.
func (k Keeper) AfterAddToPosition(ctx sdk.Context, poolId uint64, owner sdk.AccAddress, positionId uint64, amount0Added osmomath.Int, amount1Added osmomath.Int, amount0Min osmomath.Int, amount1Min osmomath.Int) error {
// Build and marshal the message to be passed to the contract
msg := types.AfterAddToPositionMsg{PoolId: poolId, Owner: owner, PositionId: positionId, Amount0Added: amount0Added, Amount1Added: amount1Added, Amount0Min: amount0Min, Amount1Min: amount1Min}
msgBz, err := json.Marshal(types.AfterAddToPositionSudoMsg{AfterAddToPosition: msg})
if err != nil {
return err
}
return k.callPoolActionListener(ctx, msgBz, poolId, afterActionPrefix(types.AddToPositionPrefix))
}

// BeforeWithdrawPosition is a hook that is called before liquidity is withdrawn from a position.
func (k Keeper) BeforeWithdrawPosition(ctx sdk.Context, poolId uint64, owner sdk.AccAddress, positionId uint64, amountToWithdraw osmomath.Dec) error {
// Build and marshal the message to be passed to the contract
msg := types.BeforeWithdrawPositionMsg{PoolId: poolId, Owner: owner, PositionId: positionId, AmountToWithdraw: amountToWithdraw}
msgBz, err := json.Marshal(types.BeforeWithdrawPositionSudoMsg{BeforeWithdrawPosition: msg})
if err != nil {
return err
}
return k.callPoolActionListener(ctx, msgBz, poolId, beforeActionPrefix(types.WithdrawPositionPrefix))
}

// AfterWithdrawPosition is a hook that is called after liquidity is withdrawn from a position.
func (k Keeper) AfterWithdrawPosition(ctx sdk.Context, poolId uint64, owner sdk.AccAddress, positionId uint64, amountToWithdraw osmomath.Dec) error {
// Build and marshal the message to be passed to the contract
msg := types.AfterWithdrawPositionMsg{PoolId: poolId, Owner: owner, PositionId: positionId, AmountToWithdraw: amountToWithdraw}
msgBz, err := json.Marshal(types.AfterWithdrawPositionSudoMsg{AfterWithdrawPosition: msg})
if err != nil {
return err
}
return k.callPoolActionListener(ctx, msgBz, poolId, afterActionPrefix(types.WithdrawPositionPrefix))
}

// BeforeSwapExactAmountIn is a hook that is called before a swap is executed (exact amount in).
func (k Keeper) BeforeSwapExactAmountIn(ctx sdk.Context, poolId uint64, sender sdk.AccAddress, tokenIn sdk.Coin, tokenOutDenom string, tokenOutMinAmount osmomath.Int, spreadFactor osmomath.Dec) error {
// Build and marshal the message to be passed to the contract
msg := types.BeforeSwapExactAmountInMsg{PoolId: poolId, Sender: sender, TokenIn: osmoutils.CWCoinFromSDKCoin(tokenIn), TokenOutDenom: tokenOutDenom, TokenOutMinAmount: tokenOutMinAmount, SpreadFactor: spreadFactor}
msgBz, err := json.Marshal(types.BeforeSwapExactAmountInSudoMsg{BeforeSwapExactAmountIn: msg})
if err != nil {
return err
}
return k.callPoolActionListener(ctx, msgBz, poolId, beforeActionPrefix(types.SwapExactAmountInPrefix))
}

// AfterSwapExactAmountIn is a hook that is called after a swap is executed (exact amount in).
func (k Keeper) AfterSwapExactAmountIn(ctx sdk.Context, poolId uint64, sender sdk.AccAddress, tokenIn sdk.Coin, tokenOutDenom string, tokenOutMinAmount osmomath.Int, spreadFactor osmomath.Dec) error {
// Build and marshal the message to be passed to the contract
msg := types.AfterSwapExactAmountInMsg{PoolId: poolId, Sender: sender, TokenIn: osmoutils.CWCoinFromSDKCoin(tokenIn), TokenOutDenom: tokenOutDenom, TokenOutMinAmount: tokenOutMinAmount, SpreadFactor: spreadFactor}
msgBz, err := json.Marshal(types.AfterSwapExactAmountInSudoMsg{AfterSwapExactAmountIn: msg})
if err != nil {
return err
}
return k.callPoolActionListener(ctx, msgBz, poolId, afterActionPrefix(types.SwapExactAmountInPrefix))
}

// BeforeSwapExactAmountOut is a hook that is called before a swap is executed (exact amount out).
func (k Keeper) BeforeSwapExactAmountOut(ctx sdk.Context, poolId uint64, sender sdk.AccAddress, tokenInDenom string, tokenInMaxAmount osmomath.Int, tokenOut sdk.Coin, spreadFactor osmomath.Dec) error {
// Build and marshal the message to be passed to the contract
msg := types.BeforeSwapExactAmountOutMsg{PoolId: poolId, Sender: sender, TokenInDenom: tokenInDenom, TokenInMaxAmount: tokenInMaxAmount, TokenOut: osmoutils.CWCoinFromSDKCoin(tokenOut), SpreadFactor: spreadFactor}
msgBz, err := json.Marshal(types.BeforeSwapExactAmountOutSudoMsg{BeforeSwapExactAmountOut: msg})
if err != nil {
return err
}
return k.callPoolActionListener(ctx, msgBz, poolId, beforeActionPrefix(types.SwapExactAmountOutPrefix))
}

// AfterSwapExactAmountOut is a hook that is called after a swap is executed (exact amount out).
func (k Keeper) AfterSwapExactAmountOut(ctx sdk.Context, poolId uint64, sender sdk.AccAddress, tokenInDenom string, tokenInMaxAmount osmomath.Int, tokenOut sdk.Coin, spreadFactor osmomath.Dec) error {
// Build and marshal the message to be passed to the contract
msg := types.AfterSwapExactAmountOutMsg{PoolId: poolId, Sender: sender, TokenInDenom: tokenInDenom, TokenInMaxAmount: tokenInMaxAmount, TokenOut: osmoutils.CWCoinFromSDKCoin(tokenOut), SpreadFactor: spreadFactor}
msgBz, err := json.Marshal(types.AfterSwapExactAmountOutSudoMsg{AfterSwapExactAmountOut: msg})
if err != nil {
return err
}
return k.callPoolActionListener(ctx, msgBz, poolId, afterActionPrefix(types.SwapExactAmountOutPrefix))
}

// callPoolActionListener processes and dispatches the passed in message to the contract corresponding to the hook
// defined by the given pool ID and action prefix (e.g. pool Id: 1, action prefix: "beforeSwap").
//
Expand Down
152 changes: 152 additions & 0 deletions x/concentrated-liquidity/types/pool_hooks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package types

import (
sdk "github.com/cosmos/cosmos-sdk/types"

wasmvmtypes "github.com/CosmWasm/wasmvm/types"

"github.com/osmosis-labs/osmosis/osmomath"
)

// Action prefixes for pool actions
const (
CreatePositionPrefix = "createPosition"
AddToPositionPrefix = "addToPosition"
WithdrawPositionPrefix = "withdrawPosition"
SwapExactAmountInPrefix = "swapExactAmountIn"
SwapExactAmountOutPrefix = "swapExactAmountOut"
)

// --- Sudo Message Wrappers ---

type BeforeCreatePositionSudoMsg struct {
BeforeCreatePosition BeforeCreatePositionMsg `json:"before_create_position"`
}

type AfterCreatePositionSudoMsg struct {
AfterCreatePosition AfterCreatePositionMsg `json:"after_create_position"`
}

type BeforeAddToPositionSudoMsg struct {
BeforeAddToPosition BeforeAddToPositionMsg `json:"before_add_to_position"`
}

type AfterAddToPositionSudoMsg struct {
AfterAddToPosition AfterAddToPositionMsg `json:"after_add_to_position"`
}

type BeforeWithdrawPositionSudoMsg struct {
BeforeWithdrawPosition BeforeWithdrawPositionMsg `json:"before_withdraw_position"`
}

type AfterWithdrawPositionSudoMsg struct {
AfterWithdrawPosition AfterWithdrawPositionMsg `json:"after_withdraw_position"`
}

type BeforeSwapExactAmountInSudoMsg struct {
BeforeSwapExactAmountIn BeforeSwapExactAmountInMsg `json:"before_swap_exact_amount_in"`
}

type AfterSwapExactAmountInSudoMsg struct {
AfterSwapExactAmountIn AfterSwapExactAmountInMsg `json:"after_swap_exact_amount_in"`
}

type BeforeSwapExactAmountOutSudoMsg struct {
BeforeSwapExactAmountOut BeforeSwapExactAmountOutMsg `json:"before_swap_exact_amount_out"`
}

type AfterSwapExactAmountOutSudoMsg struct {
AfterSwapExactAmountOut AfterSwapExactAmountOutMsg `json:"after_swap_exact_amount_out"`
}

// --- Message structs ---

type BeforeCreatePositionMsg struct {
PoolId uint64 `json:"pool_id"`
Owner sdk.AccAddress `json:"owner"`
TokensProvided wasmvmtypes.Coins `json:"tokens_provided"`
Amount0Min osmomath.Int `json:"amount_0_min"`
Amount1Min osmomath.Int `json:"amount_1_min"`
LowerTick int64 `json:"lower_tick"`
UpperTick int64 `json:"upper_tick"`
}

type AfterCreatePositionMsg struct {
PoolId uint64 `json:"pool_id"`
Owner sdk.AccAddress `json:"owner"`
TokensProvided wasmvmtypes.Coins `json:"tokens_provided"`
Amount0Min osmomath.Int `json:"amount_0_min"`
Amount1Min osmomath.Int `json:"amount_1_min"`
LowerTick int64 `json:"lower_tick"`
UpperTick int64 `json:"upper_tick"`
}

type BeforeAddToPositionMsg struct {
PoolId uint64 `json:"pool_id"`
Owner sdk.AccAddress `json:"owner"`
PositionId uint64 `json:"position_id"`
Amount0Added osmomath.Int `json:"amount_0_added"`
Amount1Added osmomath.Int `json:"amount_1_added"`
Amount0Min osmomath.Int `json:"amount_0_min"`
Amount1Min osmomath.Int `json:"amount_1_min"`
}

type AfterAddToPositionMsg struct {
PoolId uint64 `json:"pool_id"`
Owner sdk.AccAddress `json:"owner"`
PositionId uint64 `json:"position_id"`
Amount0Added osmomath.Int `json:"amount_0_added"`
Amount1Added osmomath.Int `json:"amount_1_added"`
Amount0Min osmomath.Int `json:"amount_0_min"`
Amount1Min osmomath.Int `json:"amount_1_min"`
}

type BeforeWithdrawPositionMsg struct {
PoolId uint64 `json:"pool_id"`
Owner sdk.AccAddress `json:"owner"`
PositionId uint64 `json:"position_id"`
AmountToWithdraw osmomath.Dec `json:"amount_to_withdraw"`
}

type AfterWithdrawPositionMsg struct {
PoolId uint64 `json:"pool_id"`
Owner sdk.AccAddress `json:"owner"`
PositionId uint64 `json:"position_id"`
AmountToWithdraw osmomath.Dec `json:"amount_to_withdraw"`
}

type BeforeSwapExactAmountInMsg struct {
PoolId uint64 `json:"pool_id"`
Sender sdk.AccAddress `json:"sender"`
TokenIn wasmvmtypes.Coin `json:"token_in"`
TokenOutDenom string `json:"token_out_denom"`
TokenOutMinAmount osmomath.Int `json:"token_out_min_amount"`
SpreadFactor osmomath.Dec `json:"spread_factor"`
}

type AfterSwapExactAmountInMsg struct {
PoolId uint64 `json:"pool_id"`
Sender sdk.AccAddress `json:"sender"`
TokenIn wasmvmtypes.Coin `json:"token_in"`
TokenOutDenom string `json:"token_out_denom"`
TokenOutMinAmount osmomath.Int `json:"token_out_min_amount"`
SpreadFactor osmomath.Dec `json:"spread_factor"`
}

type BeforeSwapExactAmountOutMsg struct {
PoolId uint64 `json:"pool_id"`
Sender sdk.AccAddress `json:"sender"`
TokenInDenom string `json:"token_in_denom"`
TokenInMaxAmount osmomath.Int `json:"token_in_max_amount"`
TokenOut wasmvmtypes.Coin `json:"token_out"`
SpreadFactor osmomath.Dec `json:"spread_factor"`
}

type AfterSwapExactAmountOutMsg struct {
PoolId uint64 `json:"pool_id"`
Sender sdk.AccAddress `json:"sender"`
TokenInDenom string `json:"token_in_denom"`
TokenInMaxAmount osmomath.Int `json:"token_in_max_amount"`
TokenOut wasmvmtypes.Coin `json:"token_out"`
SpreadFactor osmomath.Dec `json:"spread_factor"`
}
21 changes: 3 additions & 18 deletions x/tokenfactory/keeper/before_send.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import (

sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/osmosis-labs/osmosis/osmoutils"
"github.com/osmosis-labs/osmosis/v20/x/tokenfactory/types"

errorsmod "cosmossdk.io/errors"
wasmvmtypes "github.com/CosmWasm/wasmvm/types"
)

func (k Keeper) setBeforeSendHook(ctx sdk.Context, denom string, cosmwasmAddress string) error {
Expand Down Expand Up @@ -47,21 +47,6 @@ func (k Keeper) GetBeforeSendHook(ctx sdk.Context, denom string) string {
return string(bz)
}

func CWCoinsFromSDKCoins(in sdk.Coins) wasmvmtypes.Coins {
var cwCoins wasmvmtypes.Coins
for _, coin := range in {
cwCoins = append(cwCoins, CWCoinFromSDKCoin(coin))
}
return cwCoins
}

func CWCoinFromSDKCoin(in sdk.Coin) wasmvmtypes.Coin {
return wasmvmtypes.Coin{
Denom: in.GetDenom(),
Amount: in.Amount.String(),
}
}

// Hooks wrapper struct for bank keeper
type Hooks struct {
k Keeper
Expand Down Expand Up @@ -114,7 +99,7 @@ func (k Keeper) callBeforeSendListener(ctx sdk.Context, from, to sdk.AccAddress,
BlockBeforeSend: types.BlockBeforeSendMsg{
From: from.String(),
To: to.String(),
Amount: CWCoinFromSDKCoin(coin),
Amount: osmoutils.CWCoinFromSDKCoin(coin),
},
}
msgBz, err = json.Marshal(msg)
Expand All @@ -123,7 +108,7 @@ func (k Keeper) callBeforeSendListener(ctx sdk.Context, from, to sdk.AccAddress,
TrackBeforeSend: types.TrackBeforeSendMsg{
From: from.String(),
To: to.String(),
Amount: CWCoinFromSDKCoin(coin),
Amount: osmoutils.CWCoinFromSDKCoin(coin),
},
}
msgBz, err = json.Marshal(msg)
Expand Down

0 comments on commit 8c26c80

Please sign in to comment.