Skip to content

Commit

Permalink
feat: simulate swap as part of quotes (#547)
Browse files Browse the repository at this point in the history
* feat: simulate swap as part of quotes

* try adding e2e test

* updates

* lint

* fix test

* swagger

* attempt fix grpc wiring

* fix e2e sim test

* updates

(cherry picked from commit f2931d8)

# Conflicts:
#	domain/cosmos/tx/msg_simulator.go
#	domain/cosmos/tx/msg_simulator_test.go
#	domain/mocks/msg_simulator_mock.go
#	domain/passthrough/passthrough_grpc_client.go
  • Loading branch information
p0mvn authored and mergify[bot] committed Nov 4, 2024
1 parent ecc7019 commit f65ed41
Show file tree
Hide file tree
Showing 28 changed files with 1,269 additions and 48 deletions.
17 changes: 16 additions & 1 deletion app/sidecar_query_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,16 @@ import (
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"

"github.com/osmosis-labs/osmosis/v26/app"
txfeestypes "github.com/osmosis-labs/osmosis/v26/x/txfees/types"
"github.com/osmosis-labs/sqs/domain/cosmos/auth/types"
ingestrpcdelivry "github.com/osmosis-labs/sqs/ingest/delivery/grpc"
ingestusecase "github.com/osmosis-labs/sqs/ingest/usecase"
orderbookclaimbot "github.com/osmosis-labs/sqs/ingest/usecase/plugins/orderbook/claimbot"
orderbookfillbot "github.com/osmosis-labs/sqs/ingest/usecase/plugins/orderbook/fillbot"
orderbookrepository "github.com/osmosis-labs/sqs/orderbook/repository"
orderbookusecase "github.com/osmosis-labs/sqs/orderbook/usecase"
"github.com/osmosis-labs/sqs/quotesimulator"
"github.com/osmosis-labs/sqs/sqsutil/datafetchers"

chaininforepo "github.com/osmosis-labs/sqs/chaininfo/repository"
Expand All @@ -43,6 +47,7 @@ import (

"github.com/osmosis-labs/sqs/domain"
"github.com/osmosis-labs/sqs/domain/cache"
"github.com/osmosis-labs/sqs/domain/cosmos/tx"
"github.com/osmosis-labs/sqs/domain/keyring"
"github.com/osmosis-labs/sqs/domain/mvc"
orderbookgrpcclientdomain "github.com/osmosis-labs/sqs/domain/orderbook/grpcclient"
Expand Down Expand Up @@ -210,7 +215,17 @@ func NewSideCarQueryServer(appCodec codec.Codec, config domain.Config, logger lo
if err := tokenshttpdelivery.NewTokensHandler(e, *config.Pricing, tokensUseCase, pricingSimpleRouterUsecase, logger); err != nil {
return nil, err
}
routerHttpDelivery.NewRouterHandler(e, routerUsecase, tokensUseCase, logger)

grpcClient := passthroughGRPCClient.GetChainGRPCClient()
gasCalculator := tx.NewGasCalculator(grpcClient, tx.CalculateGas)
quoteSimulator := quotesimulator.NewQuoteSimulator(
gasCalculator,
app.GetEncodingConfig(),
txfeestypes.NewQueryClient(grpcClient),
types.NewQueryClient(grpcClient),
config.ChainID,
)
routerHttpDelivery.NewRouterHandler(e, routerUsecase, tokensUseCase, quoteSimulator, logger)

// Create a Numia HTTP client
passthroughConfig := config.Passthrough
Expand Down
20 changes: 16 additions & 4 deletions docs/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,18 @@ const docTemplate = `{
"description": "Boolean flag indicating whether to apply exponents to the spot price. False by default.",
"name": "applyExponents",
"in": "query"
},
{
"type": "string",
"description": "Address of the simulator to simulate the quote. If provided, the quote will be simulated.",
"name": "simulatorAddress",
"in": "query"
},
{
"type": "string",
"description": "Slippage tolerance multiplier for the simulation. If simulatorAddress is provided, this must be provided.",
"name": "simulationSlippageTolerance",
"in": "query"
}
],
"responses": {
Expand Down Expand Up @@ -514,7 +526,7 @@ const docTemplate = `{
"type": "object",
"properties": {
"amount": {
"$ref": "#/definitions/types.Int"
"$ref": "#/definitions/math.Int"
},
"denom": {
"type": "string"
Expand Down Expand Up @@ -663,6 +675,9 @@ const docTemplate = `{
}
}
},
"math.Int": {
"type": "object"
},
"sqsdomain.CandidatePool": {
"type": "object",
"properties": {
Expand Down Expand Up @@ -707,9 +722,6 @@ const docTemplate = `{
}
}
}
},
"types.Int": {
"type": "object"
}
}
}`
Expand Down
20 changes: 16 additions & 4 deletions docs/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,18 @@
"description": "Boolean flag indicating whether to apply exponents to the spot price. False by default.",
"name": "applyExponents",
"in": "query"
},
{
"type": "string",
"description": "Address of the simulator to simulate the quote. If provided, the quote will be simulated.",
"name": "simulatorAddress",
"in": "query"
},
{
"type": "string",
"description": "Slippage tolerance multiplier for the simulation. If simulatorAddress is provided, this must be provided.",
"name": "simulationSlippageTolerance",
"in": "query"
}
],
"responses": {
Expand Down Expand Up @@ -505,7 +517,7 @@
"type": "object",
"properties": {
"amount": {
"$ref": "#/definitions/types.Int"
"$ref": "#/definitions/math.Int"
},
"denom": {
"type": "string"
Expand Down Expand Up @@ -654,6 +666,9 @@
}
}
},
"math.Int": {
"type": "object"
},
"sqsdomain.CandidatePool": {
"type": "object",
"properties": {
Expand Down Expand Up @@ -698,9 +713,6 @@
}
}
}
},
"types.Int": {
"type": "object"
}
}
}
16 changes: 13 additions & 3 deletions docs/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ definitions:
github_com_cosmos_cosmos-sdk_types.Coin:
properties:
amount:
$ref: '#/definitions/types.Int'
$ref: '#/definitions/math.Int'
denom:
type: string
type: object
Expand Down Expand Up @@ -142,6 +142,8 @@ definitions:
$ref: '#/definitions/github_com_osmosis-labs_sqs_domain_orderbook.LimitOrder'
type: array
type: object
math.Int:
type: object
sqsdomain.CandidatePool:
properties:
id:
Expand Down Expand Up @@ -171,8 +173,6 @@ definitions:
type: object
type: object
type: object
types.Int:
type: object
info:
contact: {}
title: Osmosis Sidecar Query Server Example API
Expand Down Expand Up @@ -407,6 +407,16 @@ paths:
in: query
name: applyExponents
type: boolean
- description: Address of the simulator to simulate the quote. If provided,
the quote will be simulated.
in: query
name: simulatorAddress
type: string
- description: Slippage tolerance multiplier for the simulation. If simulatorAddress
is provided, this must be provided.
in: query
name: simulationSlippageTolerance
type: string
produces:
- application/json
responses:
Expand Down
183 changes: 183 additions & 0 deletions domain/cosmos/tx/msg_simulator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
package tx

import (
"context"

cosmosclient "github.com/cosmos/cosmos-sdk/client"
txclient "github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
sdk "github.com/cosmos/cosmos-sdk/types"
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
signingtypes "github.com/cosmos/cosmos-sdk/types/tx/signing"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/osmosis-labs/osmosis/v26/app/params"
txfeestypes "github.com/osmosis-labs/osmosis/v26/x/txfees/types"
"github.com/osmosis-labs/sqs/domain/keyring"

gogogrpc "github.com/cosmos/gogoproto/grpc"
)

// MsgSimulator is an interface for calculating gas for a transaction.
type MsgSimulator interface {
BuildTx(
ctx context.Context,
keyring keyring.Keyring,
txfeesClient txfeestypes.QueryClient,
encodingConfig params.EncodingConfig,
account *authtypes.BaseAccount,
chainID string,
msg ...sdk.Msg,
) (cosmosclient.TxBuilder, error)

// SimulateMsgs simulates the execution of the given messages and returns the simulation response,
// adjusted gas used, and any error encountered. It uses the provided gRPC client, encoding config,
// account details, and chain ID to create a transaction factory for the simulation.
SimulateMsgs(
encodingConfig cosmosclient.TxConfig,
account *authtypes.BaseAccount,
chainID string,
msgs []sdk.Msg,
) (*txtypes.SimulateResponse, uint64, error)

// PriceMsgs simulates the execution of the given messages and returns the gas used and the fee coin,
// which is the fee amount in the base denomination.
PriceMsgs(
ctx context.Context,
txfeesClient txfeestypes.QueryClient,
encodingConfig cosmosclient.TxConfig,
account *authtypes.BaseAccount,
chainID string,
msg ...sdk.Msg,
) (uint64, sdk.Coin, error)
}

// NewGasCalculator creates a new GasCalculator instance.
func NewGasCalculator(clientCtx gogogrpc.ClientConn, calculateGas CalculateGasFn) MsgSimulator {

Check failure on line 55 in domain/cosmos/tx/msg_simulator.go

View workflow job for this annotation

GitHub Actions / Run linter

NewGasCalculator redeclared in this block
return &txGasCalulator{
clientCtx: clientCtx,
calculateGas: calculateGas,
}
}

// CalculateGasFn is a function type that calculates the gas for a transaction.
type CalculateGasFn func(clientCtx gogogrpc.ClientConn, txf txclient.Factory, msgs ...sdk.Msg) (*txtypes.SimulateResponse, uint64, error)

// txGasCalulator is a GasCalculator implementation that uses simulated transactions to calculate gas.
type txGasCalulator struct {
clientCtx gogogrpc.ClientConn
calculateGas CalculateGasFn
}

// BuildTx constructs a transaction using the provided parameters and messages.
// Returns a TxBuilder and any error encountered.
func (c *txGasCalulator) BuildTx(
ctx context.Context,
keyring keyring.Keyring,
txfeesClient txfeestypes.QueryClient,
encodingConfig params.EncodingConfig,
account *authtypes.BaseAccount,
chainID string,
msg ...sdk.Msg,
) (cosmosclient.TxBuilder, error) {
key := keyring.GetKey()
privKey := &secp256k1.PrivKey{Key: key.Bytes()}

// Create and sign the transaction
txBuilder := encodingConfig.TxConfig.NewTxBuilder()

err := txBuilder.SetMsgs(msg...)
if err != nil {
return nil, err
}

gasAdjusted, feecoin, err := c.PriceMsgs(ctx, txfeesClient, encodingConfig.TxConfig, account, chainID, msg...)
if err != nil {
return nil, err
}

txBuilder.SetGasLimit(gasAdjusted)
txBuilder.SetFeeAmount(sdk.Coins{feecoin})

sigV2 := BuildSignatures(privKey.PubKey(), nil, account.Sequence)
err = txBuilder.SetSignatures(sigV2)
if err != nil {
return nil, err
}

signerData := BuildSignerData(chainID, account.AccountNumber, account.Sequence)

signed, err := txclient.SignWithPrivKey(
ctx,
signingtypes.SignMode_SIGN_MODE_DIRECT, signerData,
txBuilder, privKey, encodingConfig.TxConfig, account.Sequence)
if err != nil {
return nil, err
}

err = txBuilder.SetSignatures(signed)
if err != nil {
return nil, err
}

return txBuilder, nil
}

// SimulateMsgs implements MsgSimulator.
func (c *txGasCalulator) SimulateMsgs(encodingConfig cosmosclient.TxConfig, account *authtypes.BaseAccount, chainID string, msgs []sdk.Msg) (*txtypes.SimulateResponse, uint64, error) {
txFactory := txclient.Factory{}
txFactory = txFactory.WithTxConfig(encodingConfig)
txFactory = txFactory.WithAccountNumber(account.AccountNumber)
txFactory = txFactory.WithSequence(account.Sequence)
txFactory = txFactory.WithChainID(chainID)
txFactory = txFactory.WithGasAdjustment(1.05)

// Estimate transaction
gasResult, adjustedGasUsed, err := c.calculateGas(
c.clientCtx,
txFactory,
msgs...,
)
if err != nil {
return nil, adjustedGasUsed, err
}

return gasResult, adjustedGasUsed, nil
}

// PriceMsgs implements MsgSimulator.
func (c *txGasCalulator) PriceMsgs(ctx context.Context, txfeesClient txfeestypes.QueryClient, encodingConfig cosmosclient.TxConfig, account *authtypes.BaseAccount, chainID string, msg ...sdk.Msg) (uint64, sdk.Coin, error) {
_, gasAdjusted, err := c.SimulateMsgs(
encodingConfig,
account,
chainID,
msg,
)
if err != nil {
return 0, sdk.Coin{}, err
}

feeCoin, err := CalculateFeeCoin(ctx, txfeesClient, gasAdjusted)

Check failure on line 159 in domain/cosmos/tx/msg_simulator.go

View workflow job for this annotation

GitHub Actions / Run linter

cannot use txfeesClient (variable of type "github.com/osmosis-labs/osmosis/v26/x/txfees/types".QueryClient) as "github.com/osmosis-labs/osmosis/v27/x/txfees/types".QueryClient value in argument to CalculateFeeCoin: "github.com/osmosis-labs/osmosis/v26/x/txfees/types".QueryClient does not implement "github.com/osmosis-labs/osmosis/v27/x/txfees/types".QueryClient (wrong type for method BaseDenom)
if err != nil {
return 0, sdk.Coin{}, err
}

return gasAdjusted, feeCoin, nil
}

// CalculateGas calculates the gas required for a transaction using the provided transaction factory and messages.
func CalculateGas(
clientCtx gogogrpc.ClientConn,
txf txclient.Factory,
msgs ...sdk.Msg,
) (*txtypes.SimulateResponse, uint64, error) {
gasResult, adjustedGasUsed, err := txclient.CalculateGas(
clientCtx,
txf,
msgs...,
)
if err != nil {
return nil, adjustedGasUsed, err
}

return gasResult, adjustedGasUsed, nil
}
Loading

0 comments on commit f65ed41

Please sign in to comment.