Skip to content

Commit

Permalink
BE-658 | Add SQS ingest types
Browse files Browse the repository at this point in the history
  • Loading branch information
deividaspetraitis committed Jan 7, 2025
1 parent 9115718 commit 5ffd121
Show file tree
Hide file tree
Showing 5 changed files with 354 additions and 1 deletion.
25 changes: 25 additions & 0 deletions ingest/types/candidate_route.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package types

// CandidatePool is a data structure representing a
// candidate pool to be used for routing.
type CandidatePool struct {
ID uint64
TokenOutDenom string
}

// CandidateRoute is a data structure representing a
// candidate route to be used for routing.
type CandidateRoute struct {
Pools []CandidatePool
IsCanonicalOrderboolRoute bool
}

// CandidateRoutes is a data structure representing a
// list of candidate routes to be used for routing.
// Additionally, it encapsulates a map of unique pool IDs
// contained in the routes.
type CandidateRoutes struct {
Routes []CandidateRoute
UniquePoolIDs map[uint64]struct{}
ContainsCanonicalOrderbook bool
}
91 changes: 91 additions & 0 deletions ingest/types/pools_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package types

import (
"testing"

"github.com/stretchr/testify/assert"

sqspassthroughdomain "github.com/osmosis-labs/osmosis/v28/ingest/types/passthroughdomain"
api "github.com/osmosis-labs/sqs/pkg/api/v1beta1/pools"
)

func TestPoolWrapper_Incentive(t *testing.T) {
tests := []struct {
name string
aprData sqspassthroughdomain.PoolAPRDataStatusWrap
expected api.IncentiveType
}{
{
name: "Superfluid Incentive",
aprData: sqspassthroughdomain.PoolAPRDataStatusWrap{
PoolAPR: sqspassthroughdomain.PoolAPR{
SuperfluidAPR: sqspassthroughdomain.PoolDataRange{Lower: 1, Upper: 2},
OsmosisAPR: sqspassthroughdomain.PoolDataRange{Lower: 0, Upper: 0},
},
},
expected: api.IncentiveType_SUPERFLUID,
},
{
name: "Osmosis Incentive",
aprData: sqspassthroughdomain.PoolAPRDataStatusWrap{
PoolAPR: sqspassthroughdomain.PoolAPR{
SuperfluidAPR: sqspassthroughdomain.PoolDataRange{Lower: 0, Upper: 0},
OsmosisAPR: sqspassthroughdomain.PoolDataRange{Lower: 1, Upper: 2},
BoostAPR: sqspassthroughdomain.PoolDataRange{Lower: 0, Upper: 0},
},
},
expected: api.IncentiveType_OSMOSIS,
},
{
name: "Boost Incentive",
aprData: sqspassthroughdomain.PoolAPRDataStatusWrap{
PoolAPR: sqspassthroughdomain.PoolAPR{
BoostAPR: sqspassthroughdomain.PoolDataRange{Lower: 1, Upper: 2},
},
},
expected: api.IncentiveType_BOOST,
},
{
name: "No Incentive",
aprData: sqspassthroughdomain.PoolAPRDataStatusWrap{
PoolAPR: sqspassthroughdomain.PoolAPR{
SuperfluidAPR: sqspassthroughdomain.PoolDataRange{Lower: 0, Upper: 0},
OsmosisAPR: sqspassthroughdomain.PoolDataRange{Lower: 0, Upper: 0},
BoostAPR: sqspassthroughdomain.PoolDataRange{Lower: 0, Upper: 0},
},
},
expected: api.IncentiveType_NONE,
},
{
name: "Multiple Incentives - Superfluid Priority",
aprData: sqspassthroughdomain.PoolAPRDataStatusWrap{
PoolAPR: sqspassthroughdomain.PoolAPR{
SuperfluidAPR: sqspassthroughdomain.PoolDataRange{Lower: 1, Upper: 2},
OsmosisAPR: sqspassthroughdomain.PoolDataRange{Lower: 1, Upper: 2},
BoostAPR: sqspassthroughdomain.PoolDataRange{Lower: 1, Upper: 2},
},
},
expected: api.IncentiveType_SUPERFLUID,
},
{
name: "Multiple Incentives - Osmosis Priority",
aprData: sqspassthroughdomain.PoolAPRDataStatusWrap{
PoolAPR: sqspassthroughdomain.PoolAPR{
SuperfluidAPR: sqspassthroughdomain.PoolDataRange{Lower: 0, Upper: 0},
OsmosisAPR: sqspassthroughdomain.PoolDataRange{Lower: 1, Upper: 2},
BoostAPR: sqspassthroughdomain.PoolDataRange{Lower: 1, Upper: 2},
},
},
expected: api.IncentiveType_OSMOSIS,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
pool := &PoolWrapper{
APRData: tt.aprData,
}
assert.Equal(t, tt.expected, pool.Incentive())
})
}
}
10 changes: 10 additions & 0 deletions ingest/types/taker_fee.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package types

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

// TakerFeeForPair represents the taker fee for a pair of tokens
type TakerFeeForPair struct {
Denom0 string
Denom1 string
TakerFee osmomath.Dec
}
227 changes: 227 additions & 0 deletions ingest/types/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
package types

import (
"fmt"
"sort"
"strings"

"github.com/osmosis-labs/osmosis/osmomath"
api "github.com/osmosis-labs/sqs/pkg/api/v1beta1/pools"

ingesttypes "github.com/osmosis-labs/osmosis/v28/ingest/types"
"github.com/osmosis-labs/osmosis/v28/ingest/types/passthroughdomain"
poolmanagertypes "github.com/osmosis-labs/osmosis/v28/x/poolmanager/types"

"cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
)

type (
TakerFeeMap = ingesttypes.TakerFeeMap
TickModel = ingesttypes.TickModel
SQSPool = ingesttypes.SQSPool
DenomPair = ingesttypes.DenomPair
LiquidityDepthsWithRange = ingesttypes.LiquidityDepthsWithRange
)

var DefaultTakerFee = ingesttypes.DefaultTakerFee

type PoolI interface {
ingesttypes.PoolI

// GetAPRData gets the APR data for the pool
GetAPRData() passthroughdomain.PoolAPRDataStatusWrap

// SetAPRData sets the APR data for the pool
SetAPRData(aprData passthroughdomain.PoolAPRDataStatusWrap)

// GetFeesData gets the fees data for the pool
GetFeesData() passthroughdomain.PoolFeesDataStatusWrap

// SetFeesData sets the fees data for the pool
SetFeesData(feesData passthroughdomain.PoolFeesDataStatusWrap)

// GetLiquidityCap returns the pool liquidity capitalization
GetLiquidityCap() osmomath.Int

// SetLiquidityCap sets the liquidity capitalization to the given
// value.
SetLiquidityCap(liquidityCap osmomath.Int)

// GetLiquidityCapError returns the pool liquidity capitalization error.
GetLiquidityCapError() string

// SetLiquidityCapError sets the liquidity capitalization error
SetLiquidityCapError(liquidityCapError string)

// SetTickModel sets the tick model for the pool
// If this is not a concentrated pool, errors
SetTickModel(*TickModel) error

// Incentive returns the incentive type for the pool
Incentive() api.IncentiveType

// Validate validates the pool
// Returns nil if the pool is valid
// Returns error if the pool is invalid
Validate(minUOSMOTVL osmomath.Int) error
}

var _ PoolI = &PoolWrapper{}

type PoolWrapper struct {
ChainModel poolmanagertypes.PoolI `json:"underlying_pool"`
SQSModel ingesttypes.SQSPool `json:"sqs_model"`
APRData passthroughdomain.PoolAPRDataStatusWrap `json:"apr_data,omitempty"`
FeesData passthroughdomain.PoolFeesDataStatusWrap `json:"fees_data,omitempty"`
TickModel *ingesttypes.TickModel `json:"tick_model,omitempty"`
}

func NewPool(model poolmanagertypes.PoolI, spreadFactor osmomath.Dec, balances sdk.Coins) *PoolWrapper {
return &PoolWrapper{
ChainModel: model,
SQSModel: SQSPool{
SpreadFactor: spreadFactor,
Balances: balances,
},
}
}

// GetId implements PoolI.
func (p *PoolWrapper) GetId() uint64 {
return p.ChainModel.GetId()
}

// GetType implements PoolI.
func (p *PoolWrapper) GetType() poolmanagertypes.PoolType {
return p.ChainModel.GetType()
}

// GetPoolLiquidityCap implements PoolI.
func (p *PoolWrapper) GetPoolLiquidityCap() osmomath.Int {
return p.SQSModel.PoolLiquidityCap
}

// GetPoolDenoms implements PoolI.
func (p *PoolWrapper) GetPoolDenoms() []string {
// sort pool denoms
sort.Strings(p.SQSModel.PoolDenoms)
return p.SQSModel.PoolDenoms
}

// GetUnderlyingPool implements PoolI.
func (p *PoolWrapper) GetUnderlyingPool() poolmanagertypes.PoolI {
return p.ChainModel
}

// GetSQSPoolModel implements PoolI.
func (p *PoolWrapper) GetSQSPoolModel() SQSPool {
return p.SQSModel
}

// GetTickModel implements PoolI.
func (p *PoolWrapper) GetTickModel() (*TickModel, error) {
if p.GetType() != poolmanagertypes.Concentrated {
return nil, fmt.Errorf("pool (%d) is not a concentrated pool, type (%d)", p.GetId(), p.GetType())
}

if p.TickModel == nil {
return nil, ingesttypes.ConcentratedPoolNoTickModelError{PoolId: p.GetId()}
}

return p.TickModel, nil
}

// Incentive implements PoolI.
func (p *PoolWrapper) Incentive() api.IncentiveType {
apr := p.GetAPRData()

checks := []struct {
apr passthroughdomain.PoolDataRange
incentive api.IncentiveType
}{
{apr.SuperfluidAPR, api.IncentiveType_SUPERFLUID},
{apr.OsmosisAPR, api.IncentiveType_OSMOSIS},
{apr.BoostAPR, api.IncentiveType_BOOST},
}

for _, check := range checks {
if check.apr.Lower != 0 && check.apr.Upper != 0 {
return check.incentive
}
}

return api.IncentiveType_NONE
}

// SetTickModel implements PoolI.
func (p *PoolWrapper) SetTickModel(tickModel *TickModel) error {
if p.GetType() != poolmanagertypes.Concentrated {
return fmt.Errorf("pool (%d) is not a concentrated pool, type (%d)", p.GetId(), p.GetType())
}

p.TickModel = tickModel

return nil
}

func (p *PoolWrapper) Validate(minPoolLiquidityCapitalization osmomath.Int) error {
sqsModel := p.GetSQSPoolModel()
poolDenoms := p.GetPoolDenoms()

if len(poolDenoms) < 2 {
return fmt.Errorf("pool (%d) has fewer than 2 denoms (%d)", p.GetId(), len(poolDenoms))
}

// Note that balances are allowed to be zero because zero coins are filtered out.

// Validate pool liquidity capitalization.
// If there is no pool liquidity capitalization error set and the pool liquidity capitalization is nil or zero, return an error. This implies
// That pool has no liquidity.
poolLiquidityCapError := strings.TrimSpace(p.SQSModel.PoolLiquidityCapError)
if poolLiquidityCapError == "" && (sqsModel.PoolLiquidityCap.IsNil() || sqsModel.PoolLiquidityCap.IsZero()) {
return fmt.Errorf("pool (%d) has no liquidity, minimum pool liquidity capitalization (%s)", p.GetId(), minPoolLiquidityCapitalization)
}

return nil
}

// GetLiquidityCap implements PoolI.
func (p *PoolWrapper) GetLiquidityCap() osmomath.Int {
return p.SQSModel.PoolLiquidityCap
}

// SetLiquidityCap implements PoolI.
func (p *PoolWrapper) SetLiquidityCap(liquidityCap math.Int) {
p.SQSModel.PoolLiquidityCap = liquidityCap
}

// GetLiquidityCapError implements PoolI.
func (p *PoolWrapper) GetLiquidityCapError() string {
return p.SQSModel.PoolLiquidityCapError
}

// SetLiquidityCapError implements PoolI.
func (p *PoolWrapper) SetLiquidityCapError(liquidityCapError string) {
p.SQSModel.PoolLiquidityCapError = liquidityCapError
}

// SetAPRData implements PoolI.
func (p *PoolWrapper) SetAPRData(aprData passthroughdomain.PoolAPRDataStatusWrap) {
p.APRData = aprData
}

// SetFeesData implements PoolI.
func (p *PoolWrapper) SetFeesData(feesData passthroughdomain.PoolFeesDataStatusWrap) {
p.FeesData = feesData
}

// GetAPRData implements PoolI.
func (p *PoolWrapper) GetAPRData() passthroughdomain.PoolAPRDataStatusWrap {
return p.APRData
}

// GetFeesData implements PoolI.
func (p *PoolWrapper) GetFeesData() passthroughdomain.PoolFeesDataStatusWrap {
return p.FeesData
}
2 changes: 1 addition & 1 deletion ingest/usecase/ingest_usecase.go
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ func transferDenomLiquidityMap(transferTo, transferFrom domain.DenomPoolLiquidit
func (p *ingestUseCase) parsePool(pool *types.PoolData) (sqsingesttypes.PoolI, error) {
poolWrapper := sqsingesttypes.PoolWrapper{}

if err := p.codec.UnmarshalInterfaceJSON(pool.ChainModel, poolWrapper.ChainModel); err != nil {
if err := p.codec.UnmarshalInterfaceJSON(pool.ChainModel, &poolWrapper.ChainModel); err != nil {
return nil, err
}

Expand Down

0 comments on commit 5ffd121

Please sign in to comment.