Skip to content

Commit

Permalink
BE-586 | Claimbot (#524)
Browse files Browse the repository at this point in the history
* BE-586 | Claimbot prototype

Init

* BE-586 | WIP

* BE-586 | WIP

* BE-595 | Clean up

* BE-586 | Add docs

* BE-586 | Clean up

* BE-586 | Add docs

* BE-596 | Tests init

* BE-586 | Add tests for slices, orderbook packages

* BE-586 | claimbot/tx tests

* BE-586 | claimbot/order.go tests

* BE-586 | Requested changes

* BE-586 | Process block orderbooks, tests

* BE-586 | Requested changes

* BE-586 | Config update

* BE-586 | OrderBookClient use slices.Split for pagination

Cleans up OrderBookClient by reusing slices.Split instead of duplicating
splitting slices into chunks logic in some of the methods.

* BE-586 | Clean up

* BE-586 | Fix fillbot docker-compose

Fixes errors running fillbot via docker-compose

* BE-586 | Docs, docker compose fixes

* BE-586 | Run fillbot via docker-compose

* BE-586 | Run claimbot via docker-compose, clean up

* BE-586 | Cleanup

* BE-586 | Named logger

* BE-586 | Requested changes

* BE-586 | Logging failing tx

* BE-586 | Increase gas adjustment

* BE-586 | Error logging fix

* BE-586 | Trace name update

* BE-586 | Requested changes #1

* BE-586 | Requested changes #2

* BE-586 | Sequence number update

* BE-586 | added tests

* BE-586 | Suggested improvements
  • Loading branch information
deividaspetraitis committed Nov 25, 2024
1 parent c8e684f commit 8f2df57
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 132 deletions.
1 change: 0 additions & 1 deletion app/sidecar_query_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import (
"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"
"github.com/osmosis-labs/sqs/ingest/usecase/plugins/basefee"
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"
Expand Down
29 changes: 29 additions & 0 deletions domain/cosmos/tx/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,35 @@ func SendTx(ctx context.Context, txServiceClient txtypes.ServiceClient, txBytes
return resp.TxResponse, nil
}

// 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.
func SimulateMsgs(
gasCalculator GasCalculator,
encodingConfig params.EncodingConfig,
account *authtypes.BaseAccount,
chainID string,
msgs []sdk.Msg,
) (*txtypes.SimulateResponse, uint64, error) {
txFactory := txclient.Factory{}
txFactory = txFactory.WithTxConfig(encodingConfig.TxConfig)
txFactory = txFactory.WithAccountNumber(account.AccountNumber)
txFactory = txFactory.WithSequence(account.Sequence)
txFactory = txFactory.WithChainID(chainID)
txFactory = txFactory.WithGasAdjustment(1.15)

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

return gasResult, adjustedGasUsed, nil
}

// BuildSignatures creates a SignatureV2 object using the provided public key, signature, and sequence number.
// This is used in the process of building and signing transactions.
func BuildSignatures(publicKey cryptotypes.PubKey, signature []byte, sequence uint64) signingtypes.SignatureV2 {
Expand Down
7 changes: 4 additions & 3 deletions ingest/usecase/plugins/orderbook/claimbot/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"github.com/osmosis-labs/sqs/domain/mvc"
"github.com/osmosis-labs/sqs/log"

txfeestypes "github.com/osmosis-labs/osmosis/v27/x/txfees/types"
txfeestypes "github.com/osmosis-labs/osmosis/v26/x/txfees/types"

txtypes "github.com/cosmos/cosmos-sdk/types/tx"
)
Expand All @@ -20,7 +20,7 @@ type Config struct {
OrderbookUsecase mvc.OrderBookUsecase
AccountQueryClient authtypes.QueryClient
TxfeesClient txfeestypes.QueryClient
MsgSimulator sqstx.MsgSimulator
GasCalculator sqstx.GasCalculator
TxServiceClient txtypes.ServiceClient
ChainID string
Logger log.Logger
Expand All @@ -45,7 +45,8 @@ func NewConfig(
PoolsUseCase: poolsUseCase,
OrderbookUsecase: orderbookusecase,
AccountQueryClient: authtypes.NewQueryClient(grpcClient),
MsgSimulator: sqstx.NewMsgSimulator(grpcClient, sqstx.CalculateGas, nil),
TxfeesClient: txfeestypes.NewQueryClient(grpcClient),
GasCalculator: sqstx.NewGasCalculator(grpcClient),
TxServiceClient: txtypes.NewServiceClient(grpcClient),
Logger: logger.Named("claimbot"),
ChainID: chainID,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ services:
command:
- start
- --home=/osmosis/.osmosisd
image: osmolabs/osmosis:27.0.1
image: osmolabs/osmosis:26.0.2
container_name: osmosis
restart: always
ports:
Expand Down
16 changes: 4 additions & 12 deletions ingest/usecase/plugins/orderbook/claimbot/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ import (
"github.com/osmosis-labs/sqs/domain/mvc"
orderbookdomain "github.com/osmosis-labs/sqs/domain/orderbook"

txfeestypes "github.com/osmosis-labs/osmosis/v27/x/txfees/types"
"github.com/osmosis-labs/osmosis/v27/app/params"
txfeestypes "github.com/osmosis-labs/osmosis/v26/x/txfees/types"

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

Expand All @@ -22,12 +21,6 @@ import (
// ProcessedOrderbook is order alias data structure for testing purposes.
type ProcessedOrderbook = processedOrderbook

var (
EncodingConfig = encodingConfig

DefaultEncodingConfigFn = defaultEncodingConfigFn
)

// ProcessOrderbooksAndGetClaimableOrders is test wrapper for processOrderbooksAndGetClaimableOrders.
// This function is exported for testing purposes.
func ProcessOrderbooksAndGetClaimableOrders(
Expand All @@ -41,19 +34,18 @@ func ProcessOrderbooksAndGetClaimableOrders(

// SendBatchClaimTx a test wrapper for sendBatchClaimTx.
// This function is used only for testing purposes.
func SendBatchClaimTxInternal(
func SendBatchClaimTx(
ctx context.Context,
keyring keyring.Keyring,
txfeesClient txfeestypes.QueryClient,
msgSimulator sqstx.MsgSimulator,
gasCalculator sqstx.GasCalculator,
txServiceClient txtypes.ServiceClient,
chainID string,
account *authtypes.BaseAccount,
contractAddress string,
claims orderbookdomain.Orders,
getEncodingConfig func() params.EncodingConfig,
) (*sdk.TxResponse, error) {
return sendBatchClaimTxInternal(ctx, keyring, msgSimulator, txServiceClient, chainID, account, contractAddress, claims, getEncodingConfig)
return sendBatchClaimTx(ctx, keyring, txfeesClient, gasCalculator, txServiceClient, chainID, account, contractAddress, claims)
}

// PrepareBatchClaimMsg is a test wrapper for prepareBatchClaimMsg.
Expand Down
3 changes: 2 additions & 1 deletion ingest/usecase/plugins/orderbook/claimbot/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,8 @@ func (o *claimbot) processOrderbookOrders(ctx context.Context, account *authtype
txres, err := sendBatchClaimTx(
ctx,
o.config.Keyring,
o.config.MsgSimulator,
o.config.TxfeesClient,
o.config.GasCalculator,
o.config.TxServiceClient,
o.config.ChainID,
account,
Expand Down
35 changes: 7 additions & 28 deletions ingest/usecase/plugins/orderbook/claimbot/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,53 +9,32 @@ import (
"github.com/osmosis-labs/sqs/domain/keyring"
orderbookdomain "github.com/osmosis-labs/sqs/domain/orderbook"

"github.com/osmosis-labs/osmosis/v26/app"
txfeestypes "github.com/osmosis-labs/osmosis/v26/x/txfees/types"

wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types"
sdk "github.com/cosmos/cosmos-sdk/types"
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/osmosis-labs/osmosis/v27/app"
"github.com/osmosis-labs/osmosis/v27/app/params"
)

var (
// Note: we monkey patch the encoding config in tests
encodingConfig params.EncodingConfig = app.MakeEncodingConfig()

defaultEncodingConfigFn = func() params.EncodingConfig {
return encodingConfig
}
encodingConfig = app.MakeEncodingConfig()
)

// sendBatchClaimTx prepares and sends a batch claim transaction to the blockchain.
// It builds the transaction, signs it, and broadcasts it to the network.
func sendBatchClaimTx(
ctx context.Context,
keyring keyring.Keyring,
msgSimulator sqstx.MsgSimulator,
txServiceClient txtypes.ServiceClient,
chainID string,
account *authtypes.BaseAccount,
contractAddress string,
claims orderbookdomain.Orders,
) (*sdk.TxResponse, error) {
return sendBatchClaimTxInternal(ctx, keyring, msgSimulator, txServiceClient, chainID, account, contractAddress, claims, defaultEncodingConfigFn)
}

// sendBatchClaimTxInternal is a helper function that prepares and sends a batch claim transaction to the blockchain.
// It takes an encoding config function as a parameter to allow for customization of the encoding config in tests.
func sendBatchClaimTxInternal(
ctx context.Context,
keyring keyring.Keyring,
msgSimulator sqstx.MsgSimulator,
txfeesClient txfeestypes.QueryClient,
gasCalculator sqstx.GasCalculator,
txServiceClient txtypes.ServiceClient,
chainID string,
account *authtypes.BaseAccount,
contractAddress string,
claims orderbookdomain.Orders,
getEncodingConfig func() params.EncodingConfig,
) (*sdk.TxResponse, error) {
encodingConfig := getEncodingConfig()

address := keyring.GetAddress().String()

msgBytes, err := prepareBatchClaimMsg(claims)
Expand All @@ -65,7 +44,7 @@ func sendBatchClaimTxInternal(

msg := buildExecuteContractMsg(address, contractAddress, msgBytes)

tx, err := msgSimulator.BuildTx(ctx, keyring, encodingConfig, account, chainID, msg)
tx, err := sqstx.BuildTx(ctx, keyring, txfeesClient, gasCalculator, encodingConfig, account, chainID, msg)
if err != nil {
return nil, fmt.Errorf("failed to build transaction: %w", err)
}
Expand Down
111 changes: 25 additions & 86 deletions ingest/usecase/plugins/orderbook/claimbot/tx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,26 @@ import (
"context"
"testing"

cosmosclient "github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/types"
sdk "github.com/cosmos/cosmos-sdk/types"
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/x/auth/signing"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/osmosis-labs/osmosis/v27/app"
"github.com/osmosis-labs/osmosis/v27/app/params"
"github.com/osmosis-labs/sqs/domain/keyring"
"github.com/osmosis-labs/sqs/domain/mocks"
orderbookdomain "github.com/osmosis-labs/sqs/domain/orderbook"
"github.com/osmosis-labs/sqs/ingest/usecase/plugins/orderbook/claimbot"

sdk "github.com/cosmos/cosmos-sdk/types"
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"

"github.com/stretchr/testify/assert"
"google.golang.org/grpc"
)

func TestSendBatchClaimTx(t *testing.T) {
const mockedTxBytes = "mocked-tx-bytes"

tests := []struct {
name string
chainID string
contractAddress string
claims orderbookdomain.Orders
setupMocks func(*mocks.Keyring, *authtypes.BaseAccount, *mocks.TxFeesQueryClient, *mocks.MsgSimulatorMock, *mocks.TxServiceClient)
setSendTxFunc func() []byte

getEncodingConfigFn func() params.EncodingConfig

name string
chainID string
contractAddress string
claims orderbookdomain.Orders
setupMocks func(*mocks.Keyring, *authtypes.BaseAccount, *mocks.TxFeesQueryClient, *mocks.GasCalculator, *mocks.TxServiceClient)
setSendTxFunc func() []byte
expectedResponse *sdk.TxResponse
expectedError bool
}{
Expand All @@ -42,52 +33,28 @@ func TestSendBatchClaimTx(t *testing.T) {
claims: orderbookdomain.Orders{
{TickId: 13, OrderId: 99},
},
setupMocks: func(keyringMock *mocks.Keyring, account *authtypes.BaseAccount, txfeesClient *mocks.TxFeesQueryClient, msgSimulator *mocks.MsgSimulatorMock, txServiceClient *mocks.TxServiceClient) {
setupMocks: func(keyringMock *mocks.Keyring, account *authtypes.BaseAccount, txfeesClient *mocks.TxFeesQueryClient, gasCalculator *mocks.GasCalculator, txServiceClient *mocks.TxServiceClient) {
keyringMock.WithGetAddress("osmo0address")
keyringMock.WithGetKey("6cf5103c60c939a5f38e383b52239c5296c968579eec1c68a47d70fbf1d19159")
account = &authtypes.BaseAccount{
AccountNumber: 3,
Sequence: 31,
}
// Fail BuildTx
msgSimulator.BuildTxFn = func(
ctx context.Context,
keyring keyring.Keyring,
encodingConfig params.EncodingConfig,
account *authtypes.BaseAccount,
chainID string,
msg ...sdk.Msg,
) (cosmosclient.TxBuilder, error) {
return nil, assert.AnError
}
gasCalculator.WithCalculateGas(nil, 0, assert.AnError) // Fail BuildTx
},
getEncodingConfigFn: claimbot.DefaultEncodingConfigFn,
expectedResponse: &sdk.TxResponse{},
expectedError: true,
expectedResponse: &sdk.TxResponse{},
expectedError: true,
},
{
name: "SendTx returns error",
contractAddress: "osmo1contractaddress",
claims: orderbookdomain.Orders{
{TickId: 13, OrderId: 99},
},
setupMocks: func(keyringMock *mocks.Keyring, account *authtypes.BaseAccount, txfeesClient *mocks.TxFeesQueryClient, msgSimulator *mocks.MsgSimulatorMock, txServiceClient *mocks.TxServiceClient) {
setupMocks: func(keyringMock *mocks.Keyring, account *authtypes.BaseAccount, txfeesClient *mocks.TxFeesQueryClient, gasCalculator *mocks.GasCalculator, txServiceClient *mocks.TxServiceClient) {
keyringMock.WithGetAddress("osmo5address")
keyringMock.WithGetKey("6cf5103c60c939a5f38e383b52239c5296c968579eec1c68a47d70fbf1d19159")
msgSimulator.BuildTxFn = func(
ctx context.Context,
keyring keyring.Keyring,
encodingConfig params.EncodingConfig,
account *authtypes.BaseAccount,
chainID string,
msg ...sdk.Msg,
) (cosmosclient.TxBuilder, error) {
return &mocks.TxBuilderMock{
GetTxFn: func() signing.Tx {
return &mocks.TxMock{}
},
}, nil
}
gasCalculator.WithCalculateGas(nil, 51, nil)
txfeesClient.WithBaseDenom("uosmo", nil)
txfeesClient.WithGetEipBaseFee("0.2", nil)
account = &authtypes.BaseAccount{
Expand All @@ -96,9 +63,8 @@ func TestSendBatchClaimTx(t *testing.T) {
}
txServiceClient.WithBroadcastTx(nil, assert.AnError) // SendTx returns error
},
getEncodingConfigFn: claimbot.DefaultEncodingConfigFn,
expectedResponse: &sdk.TxResponse{},
expectedError: true,
expectedResponse: &sdk.TxResponse{},
expectedError: true,
},
{
name: "Successful transaction",
Expand All @@ -108,23 +74,10 @@ func TestSendBatchClaimTx(t *testing.T) {
{TickId: 1, OrderId: 100},
{TickId: 2, OrderId: 200},
},
setupMocks: func(keyringMock *mocks.Keyring, account *authtypes.BaseAccount, txfeesClient *mocks.TxFeesQueryClient, msgSimulator *mocks.MsgSimulatorMock, txServiceClient *mocks.TxServiceClient) {
setupMocks: func(keyringMock *mocks.Keyring, account *authtypes.BaseAccount, txfeesClient *mocks.TxFeesQueryClient, gasCalculator *mocks.GasCalculator, txServiceClient *mocks.TxServiceClient) {
keyringMock.WithGetAddress("osmo1address")
keyringMock.WithGetKey("6cf5103c60c939a5f38e383b52239c5296c968579eec1c68a47d70fbf1d19159")
msgSimulator.BuildTxFn = func(
ctx context.Context,
keyring keyring.Keyring,
encodingConfig params.EncodingConfig,
account *authtypes.BaseAccount,
chainID string,
msg ...sdk.Msg,
) (cosmosclient.TxBuilder, error) {
return &mocks.TxBuilderMock{
GetTxFn: func() signing.Tx {
return &mocks.TxMock{}
},
}, nil
}
gasCalculator.WithCalculateGas(nil, 51, nil)
txfeesClient.WithBaseDenom("uosmo", nil)
txfeesClient.WithGetEipBaseFee("0.15", nil)
account = &authtypes.BaseAccount{
Expand All @@ -140,21 +93,8 @@ func TestSendBatchClaimTx(t *testing.T) {
}, nil
}
},

getEncodingConfigFn: func() params.EncodingConfig {
encoding := app.MakeEncodingConfig()
encoding.TxConfig = &mocks.TxConfigMock{
TxEncoderFn: func() types.TxEncoder {
return func(tx types.Tx) ([]byte, error) {
return []byte(mockedTxBytes), nil
}
},
}
return encoding
},

expectedResponse: &sdk.TxResponse{
Data: string(mockedTxBytes),
Data: "\n\x90\x01\n\x8d\x01\n$/cosmwasm.wasm.v1.MsgExecuteContract\x12e\n\x1fosmo1daek6me3v9jxgun9wdes7m4n5q\x12\x14osmo1contractaddress\x1a,{\"batch_claim\":{\"orders\":[[1,100],[2,200]]}}\x12`\nN\nF\n\x1f/cosmos.crypto.secp256k1.PubKey\x12#\n!\x03\xef]m\xf2\x8a\bx\x1f\x9a%v]E\x9e\x96\xa8\x9dc6a\x1d\x1f\x8a\xb4\xd3/q,֍\xd3\xd0\x12\x04\n\x02\b\x01\x12\x0e\n\n\n\x05uosmo\x12\x018\x103\x1a@\x1dI\xb5/D\xd0L\v2\xacg\x91\xb3;b+\xdb\xf6\xe0\x1c\x92\xee\xb8d\xc4&%<ڵ\x81\xd6u\xeb-\xf0\xf5\xa8);\x19\xfc%@\r\xfb2\x05AI\x13\xf3)=\n\xcf~\xb0\"\xf0\xb1",
},
expectedError: false,
},
Expand All @@ -166,13 +106,12 @@ func TestSendBatchClaimTx(t *testing.T) {
keyring := mocks.Keyring{}
account := authtypes.BaseAccount{}
txFeesClient := mocks.TxFeesQueryClient{}
gasCalculator := mocks.GasCalculator{}
txServiceClient := mocks.TxServiceClient{}

txSimulatorMock := mocks.MsgSimulatorMock{}

tt.setupMocks(&keyring, &account, &txFeesClient, &txSimulatorMock, &txServiceClient)
tt.setupMocks(&keyring, &account, &txFeesClient, &gasCalculator, &txServiceClient)

response, err := claimbot.SendBatchClaimTxInternal(ctx, &keyring, &txFeesClient, &txSimulatorMock, &txServiceClient, tt.chainID, &account, tt.contractAddress, tt.claims, tt.getEncodingConfigFn)
response, err := claimbot.SendBatchClaimTx(ctx, &keyring, &txFeesClient, &gasCalculator, &txServiceClient, tt.chainID, &account, tt.contractAddress, tt.claims)
if tt.expectedError {
assert.Error(t, err)
} else {
Expand Down

0 comments on commit 8f2df57

Please sign in to comment.