diff --git a/hard-keeper-bot/grpc_client.go b/hard-keeper-bot/grpc_client.go new file mode 100644 index 0000000..b17c3ca --- /dev/null +++ b/hard-keeper-bot/grpc_client.go @@ -0,0 +1,143 @@ +package main + +import ( + "context" + "crypto/tls" + "fmt" + "log" + "net/url" + "strconv" + + "github.com/cosmos/cosmos-sdk/client/grpc/tmservice" + sdk "github.com/cosmos/cosmos-sdk/types" + grpctypes "github.com/cosmos/cosmos-sdk/types/grpc" + txtypes "github.com/cosmos/cosmos-sdk/types/tx" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + hardtypes "github.com/kava-labs/kava/x/hard/types" + pricefeedtypes "github.com/kava-labs/kava/x/pricefeed/types" + + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/metadata" +) + +type GrpcClient struct { + GrpcClientConn *grpc.ClientConn + Auth authtypes.QueryClient + Tx txtypes.ServiceClient + Tm tmservice.ServiceClient + Hard hardtypes.QueryClient + Pricefeed pricefeedtypes.QueryClient +} + +var _ LiquidationClient = (*GrpcClient)(nil) + +func ctxAtHeight(height int64) context.Context { + heightStr := strconv.FormatInt(height, 10) + return metadata.AppendToOutgoingContext(context.Background(), grpctypes.GRPCBlockHeightHeader, heightStr) +} + +func NewGrpcClient(target string) GrpcClient { + grpcUrl, err := url.Parse(target) + if err != nil { + log.Fatal(err) + } + + var secureOpt grpc.DialOption + switch grpcUrl.Scheme { + case "http": + secureOpt = grpc.WithInsecure() + case "https": + creds := credentials.NewTLS(&tls.Config{}) + secureOpt = grpc.WithTransportCredentials(creds) + default: + log.Fatalf("unknown rpc url scheme %s\n", grpcUrl.Scheme) + } + + grpcConn, err := grpc.Dial(grpcUrl.Host, secureOpt) + if err != nil { + panic(err) + } + + return GrpcClient{ + GrpcClientConn: grpcConn, + Tm: tmservice.NewServiceClient(grpcConn), + Hard: hardtypes.NewQueryClient(grpcConn), + Pricefeed: pricefeedtypes.NewQueryClient(grpcConn), + } +} + +func (c GrpcClient) GetInfo() (*InfoResponse, error) { + latestBlock, err := c.Tm.GetLatestBlock(context.Background(), &tmservice.GetLatestBlockRequest{}) + if err != nil { + return nil, fmt.Errorf("failed to fetch latest block: %w", err) + } + + return &InfoResponse{ + ChainId: latestBlock.Block.Header.ChainID, + LatestHeight: latestBlock.Block.Header.Height, + }, nil +} + +func (c GrpcClient) GetPrices(height int64) (pricefeedtypes.CurrentPrices, error) { + pricesRes, err := c.Pricefeed.Prices(ctxAtHeight(height), &pricefeedtypes.QueryPricesRequest{}) + if err != nil { + return nil, err + } + + var prices []pricefeedtypes.CurrentPrice + for _, response := range pricesRes.Prices { + price := pricefeedtypes.CurrentPrice{ + MarketID: response.MarketID, + Price: response.Price, + } + prices = append(prices, price) + } + + return prices, nil +} + +func (c GrpcClient) GetMarkets(height int64) (hardtypes.MoneyMarkets, error) { + paramsRes, err := c.Hard.Params(ctxAtHeight(height), &hardtypes.QueryParamsRequest{}) + if err != nil { + return nil, err + } + + return paramsRes.Params.MoneyMarkets, nil +} + +func (c GrpcClient) GetBorrows(height int64) (hardtypes.Borrows, error) { + borrowRes, err := c.Hard.Borrows(ctxAtHeight(height), &hardtypes.QueryBorrowsRequest{}) + if err != nil { + return nil, err + } + + var borrows []hardtypes.Borrow + for _, response := range borrowRes.Borrows { + borrow := hardtypes.Borrow{ + Borrower: sdk.AccAddress(response.Borrower), + Amount: response.Amount, + } + borrows = append(borrows, borrow) + } + + return borrows, nil +} + +func (c GrpcClient) GetDeposits(height int64) (hardtypes.Deposits, error) { + depositRes, err := c.Hard.Deposits(ctxAtHeight(height), &hardtypes.QueryDepositsRequest{}) + if err != nil { + return nil, err + } + + var deposits []hardtypes.Deposit + for _, response := range depositRes.Deposits { + deposit := hardtypes.Deposit{ + Depositor: sdk.AccAddress(response.Depositor), + Amount: response.Amount, + } + deposits = append(deposits, deposit) + } + + return deposits, nil +} diff --git a/hard-keeper-bot/main.go b/hard-keeper-bot/main.go index 6758e34..588c082 100644 --- a/hard-keeper-bot/main.go +++ b/hard-keeper-bot/main.go @@ -12,13 +12,11 @@ import ( "github.com/cosmos/cosmos-sdk/client/grpc/tmservice" "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" - 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/kava-labs/go-tools/signing" "github.com/kava-labs/kava/app" "github.com/rs/zerolog" - rpchttpclient "github.com/tendermint/tendermint/rpc/client/http" "google.golang.org/grpc" "google.golang.org/grpc/credentials" ) @@ -49,11 +47,7 @@ func main() { log.Fatalf("unknown rpc url scheme %s\n", grpcUrl.Scheme) } - http, err := rpchttpclient.New(config.KavaRpcUrl, "/websocket") - if err != nil { - logger.Fatal().Err(err).Send() - } - liquidationClient := NewRpcLiquidationClient(http, encodingConfig.Amino) + liquidationClient := NewGrpcClient(config.KavaGrpcUrl) conn, err := grpc.Dial(grpcUrl.Host, secureOpt) if err != nil { @@ -134,12 +128,12 @@ func main() { for _, msg := range msgs { fmt.Printf("sending liquidation for %s\n", msg.Borrower) - requests <- signing.MsgRequest{ - Msgs: []sdk.Msg{&msg}, - GasLimit: 1000000, - FeeAmount: sdk.Coins{sdk.Coin{Denom: "ukava", Amount: sdk.NewInt(50000)}}, - Memo: "", - } + // requests <- signing.MsgRequest{ + // Msgs: []sdk.Msg{&msg}, + // GasLimit: 1000000, + // FeeAmount: sdk.Coins{sdk.Coin{Denom: "ukava", Amount: sdk.NewInt(50000)}}, + // Memo: "", + // } } // wait for next interval