Skip to content

Commit

Permalink
feat(client): Use indexer instead of hub to get orders
Browse files Browse the repository at this point in the history
feat(client): Use indexer instead of hub to get orders
  • Loading branch information
omritoptix authored May 4, 2024
2 parents 1e6a2c3 + 7f16f7d commit 06122bb
Show file tree
Hide file tree
Showing 5 changed files with 232 additions and 57 deletions.
5 changes: 5 additions & 0 deletions cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ var startCmd = &cobra.Command{
log.Fatalf("failed to create order client: %v", err)
}

if config.Bots.NumberOfBots == 0 {
log.Println("no bots to start")
return
}

if err := oc.start(cmd.Context()); err != nil {
log.Fatalf("failed to start order client: %v", err)
}
Expand Down
11 changes: 7 additions & 4 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type Config struct {
OrderRefreshInterval time.Duration `mapstructure:"order_refresh_interval"`
OrderCleanupInterval time.Duration `mapstructure:"order_cleanup_interval"`
DisputePeriodRefreshInterval time.Duration `mapstructure:"dispute_period_refresh_interval"`
IndexerURL string `mapstructure:"indexer_url"`

Whale whaleConfig `mapstructure:"whale"`
Bots botConfig `mapstructure:"bots"`
Expand Down Expand Up @@ -53,13 +54,14 @@ type slackConfig struct {

const (
defaultNodeAddress = "http://localhost:36657"
defaultIndexerURL = "http://44.206.211.230:3000/"
hubAddressPrefix = "dym"
pubKeyPrefix = "pub"
defaultLogLevel = "info"
defaultGasLimit = 300000
defaultGasDenom = "adym"
defaultGasFees = "100000000000000000" + defaultGasDenom
defaultMinimumGasBalance = "40000000000" + defaultGasDenom
defaultHubDenom = "adym"
defaultGasFees = "100000000000000000" + defaultHubDenom
defaultMinimumGasBalance = "40000000000" + defaultHubDenom
testKeyringBackend = "test"

botNamePrefix = "bot-"
Expand All @@ -73,7 +75,7 @@ const (
defaultDisputePeriodRefreshInterval = 10 * time.Hour
)

var defaultBalanceThresholds = map[string]string{defaultGasDenom: "1000000000000"}
var defaultBalanceThresholds = map[string]string{defaultHubDenom: "1000000000000"}

func initConfig() {
// Set default values
Expand Down Expand Up @@ -104,6 +106,7 @@ func initConfig() {
viper.SetDefault("slack.enabled", false)
viper.SetDefault("slack.app_token", "<your-slack-app-token>")
viper.SetDefault("slack.channel_id", "<your-slack-channel-id>")
viper.SetDefault("indexer_url", defaultIndexerURL)

viper.SetConfigType("yaml")
if cfgFile != "" {
Expand Down
68 changes: 68 additions & 0 deletions denom.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package main

import (
"context"
"fmt"
"strings"
"sync"

"github.com/cosmos/ibc-go/v6/modules/apps/transfer/types"

"github.com/dymensionxyz/cosmosclient/cosmosclient"
)

type denomFetcher struct {
sync.Mutex
pathMap map[string]string
client cosmosclient.Client
}

func newDenomFetcher(client cosmosclient.Client) *denomFetcher {
return &denomFetcher{
pathMap: make(map[string]string),
client: client,
}

}

func (d *denomFetcher) getDenomFromPath(ctx context.Context, path, destChannel string) (string, error) {
zeroChannelPrefix := "transfer/channel-0/"

// Remove "transfer/channel-0/" prefix if it exists
path = strings.TrimPrefix(path, zeroChannelPrefix)

if path == defaultHubDenom {
return defaultHubDenom, nil
}

// for denoms other than adym we should have a full path
// in order to be albe to derive the ibc denom hash
if !strings.Contains(path, "channel-") {
path = fmt.Sprintf("transfer/%s/%s", destChannel, path)
}

d.Lock()
defer d.Unlock()

denom, ok := d.pathMap[path]
if ok {
return denom, nil
}

queryClient := types.NewQueryClient(d.client.Context())

req := &types.QueryDenomHashRequest{
Trace: path,
}

res, err := queryClient.DenomHash(ctx, req)
if err != nil {
return "", fmt.Errorf("failed to query denom hash: %w", err)
}

ibcDenom := fmt.Sprintf("ibc/%s", res.Hash)

d.pathMap[path] = ibcDenom

return ibcDenom, nil
}
85 changes: 50 additions & 35 deletions order_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,18 @@ func newOrderClient(ctx context.Context, config Config) (*orderClient, error) {
return nil, fmt.Errorf("failed to create cosmos client: %w", err)
}

denomFetch := newDenomFetcher(fetcherCosmosClient)
orderCh := make(chan []*demandOrder, newOrderBufferSize)
failedCh := make(chan []string, newOrderBufferSize) // TODO: make buffer size configurable
ordFetcher := newOrderFetcher(fetcherCosmosClient, config.Bots.MaxOrdersPerTx, orderCh, failedCh, logger)
ordFetcher := newOrderFetcher(
fetcherCosmosClient,
denomFetch,
config.IndexerURL,
config.Bots.MaxOrdersPerTx,
orderCh,
failedCh,
logger,
)
topUpCh := make(chan topUpRequest, config.Bots.NumberOfBots) // TODO: make buffer size configurable
bin := "dymd" // TODO: from config

Expand All @@ -80,7 +89,6 @@ func newOrderClient(ctx context.Context, config Config) (*orderClient, error) {
}

numFoundBots := len(accs)
logger.Info("found local bot accounts", zap.Int("accounts", numFoundBots))

botsAccountsToCreate := max(0, config.Bots.NumberOfBots) - numFoundBots
if botsAccountsToCreate > 0 {
Expand Down Expand Up @@ -133,6 +141,8 @@ func newOrderClient(ctx context.Context, config Config) (*orderClient, error) {
return nil, fmt.Errorf("failed to get whale address: %w", err)
}

logger.Info("refunding funds from extra bots to whale", zap.String("whale", whaleAddr.String()))

refundFromExtraBotsToWhale(ctx, config, botIdx, accs, whaleAddr.String(), config.GasFees, logger)

oc := &orderClient{
Expand All @@ -146,10 +156,39 @@ func newOrderClient(ctx context.Context, config Config) (*orderClient, error) {
return oc, nil
}

func (oc *orderClient) start(ctx context.Context) error {
oc.logger.Info("starting demand order fetcher...")

// start order fetcher
if err := oc.orderFetcher.start(ctx, oc.config.OrderRefreshInterval, oc.config.OrderCleanupInterval); err != nil {
return fmt.Errorf("failed to subscribe to demand orders: %w", err)
}

// start whale service
if err := oc.whale.start(ctx); err != nil {
return fmt.Errorf("failed to start whale service: %w", err)
}
// oc.disputePeriodUpdater(ctx)

oc.logger.Info("starting bots...")
// start bots
for _, b := range oc.bots {
go func() {
if err := b.start(ctx); err != nil {
oc.logger.Error("failed to bot", zap.Error(err))
}
}()
}

make(chan struct{}) <- struct{}{} // TODO: make nicer

return nil
}

func refundFromExtraBotsToWhale(
ctx context.Context,
config Config,
botIdx int,
startBotIdx int,
accs []string,
whaleAddress string,
gasFeesStr string,
Expand All @@ -164,10 +203,10 @@ func refundFromExtraBotsToWhale(
}

// return funds from extra bots to whale
for ; botIdx < len(accs); botIdx++ {
for ; startBotIdx < len(accs); startBotIdx++ {
b, err := buildBot(
ctx,
accs[botIdx],
accs[startBotIdx],
logger,
config.Bots,
config.NodeAddress,
Expand Down Expand Up @@ -198,45 +237,21 @@ func refundFromExtraBotsToWhale(
continue
}

// TODO: specify the whale as the fee payer
if err = b.fulfiller.accountSvc.sendCoins(botBalances, whaleAddress); err != nil {
logger.Error("failed to return funds to whale", zap.Error(err))
continue
}

refunded = refunded.Add(botBalances...)
}

logger.Info("refunded funds from extra bots to whale",
zap.Int("bots", len(accs)-config.Bots.NumberOfBots), zap.String("refunded", refunded.String()))
}
// TODO: if EMPTY, delete the bot account

func (oc *orderClient) start(ctx context.Context) error {
oc.logger.Info("starting demand order fetcher...")

// start order fetcher
if err := oc.orderFetcher.start(ctx, oc.config.OrderRefreshInterval, oc.config.OrderCleanupInterval); err != nil {
return fmt.Errorf("failed to subscribe to demand orders: %w", err)
}

// start whale service
if err := oc.whale.start(ctx); err != nil {
return fmt.Errorf("failed to start whale service: %w", err)
refunded = refunded.Add(botBalances...)
}
// oc.disputePeriodUpdater(ctx)

oc.logger.Info("starting bots...")
// start bots
for _, b := range oc.bots {
go func() {
if err := b.start(ctx); err != nil {
oc.logger.Error("failed to bot", zap.Error(err))
}
}()
if !refunded.Empty() {
logger.Info("refunded funds from extra bots to whale",
zap.Int("bots", len(accs)-config.Bots.NumberOfBots), zap.String("refunded", refunded.String()))
}

make(chan struct{}) <- struct{}{} // TODO: make nicer

return nil
}

// add command that creates all the bots to be used?
Expand Down
Loading

0 comments on commit 06122bb

Please sign in to comment.