-
Notifications
You must be signed in to change notification settings - Fork 3
Feat/copytrader #142
Feat/copytrader #142
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,55 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| package main | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "fmt" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "os" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "strings" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "github.com/spf13/viper" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "github.com/vultisig/verifier/vault_config" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "github.com/vultisig/plugin/api" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "github.com/vultisig/plugin/storage" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type CopytraderServerConfig struct { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Server api.ServerConfig `mapstructure:"server" json:"server"` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Database struct { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| DSN string `mapstructure:"dsn" json:"dsn,omitempty"` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } `mapstructure:"database" json:"database,omitempty"` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| BaseConfigPath string `mapstructure:"base_config_path" json:"base_config_path,omitempty"` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Redis storage.RedisConfig `mapstructure:"redis" json:"redis,omitempty"` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| BlockStorage vault_config.BlockStorage `mapstructure:"block_storage" json:"block_storage,omitempty"` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Datadog struct { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Host string `mapstructure:"host" json:"host,omitempty"` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Port string `mapstructure:"port" json:"port,omitempty"` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } `mapstructure:"datadog" json:"datadog"` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func GetConfigure() (*CopytraderServerConfig, error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| configName := os.Getenv("VS_CONFIG_NAME") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if configName == "" { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| configName = "config" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return ReadConfig(configName) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func ReadConfig(configName string) (*CopytraderServerConfig, error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| viper.SetConfigName(configName) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| viper.AddConfigPath(".") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| viper.AutomaticEnv() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| viper.SetDefault("Server.VaultsFilePath", "vaults") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err := viper.ReadInConfig(); err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return nil, fmt.Errorf("failed to read config file, %w", err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var cfg CopytraderServerConfig | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| err := viper.Unmarshal(&cfg) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return nil, fmt.Errorf("unable to decode into struct, %w", err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return &cfg, nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+38
to
+55
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add configuration validation The configuration loading doesn't validate required fields, which could lead to runtime errors. Add validation after unmarshaling: var cfg CopytraderServerConfig
err := viper.Unmarshal(&cfg)
if err != nil {
return nil, fmt.Errorf("unable to decode into struct, %w", err)
}
+
+ // Validate required fields
+ if cfg.Database.DSN == "" {
+ return nil, fmt.Errorf("database DSN is required")
+ }
+ if cfg.Redis.Host == "" || cfg.Redis.Port == "" {
+ return nil, fmt.Errorf("redis host and port are required")
+ }
+
return &cfg, nil📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,102 @@ | ||||||
| package main | ||||||
|
|
||||||
| import ( | ||||||
| "context" | ||||||
| "fmt" | ||||||
| "net" | ||||||
|
|
||||||
| "github.com/DataDog/datadog-go/statsd" | ||||||
| "github.com/hibiken/asynq" | ||||||
| "github.com/sirupsen/logrus" | ||||||
| "github.com/vultisig/plugin/plugin/copytrader" | ||||||
| "github.com/vultisig/verifier/tx_indexer" | ||||||
| tx_indexer_storage "github.com/vultisig/verifier/tx_indexer/pkg/storage" | ||||||
| "github.com/vultisig/verifier/vault" | ||||||
|
|
||||||
| "github.com/vultisig/plugin/api" | ||||||
| "github.com/vultisig/plugin/storage" | ||||||
| "github.com/vultisig/plugin/storage/postgres" | ||||||
| ) | ||||||
|
|
||||||
| func main() { | ||||||
| ctx := context.Background() | ||||||
|
|
||||||
| cfg, err := GetConfigure() | ||||||
| if err != nil { | ||||||
| panic(err) | ||||||
| } | ||||||
| logger := logrus.New() | ||||||
|
|
||||||
| sdClient, err := statsd.New(net.JoinHostPort(cfg.Datadog.Host, cfg.Datadog.Port)) | ||||||
| if err != nil { | ||||||
| panic(err) | ||||||
| } | ||||||
| redisStorage, err := storage.NewRedisStorage(cfg.Redis) | ||||||
| if err != nil { | ||||||
| panic(err) | ||||||
| } | ||||||
| redisOptions := asynq.RedisClientOpt{ | ||||||
| Addr: net.JoinHostPort(cfg.Redis.Host, cfg.Redis.Port), | ||||||
| Username: cfg.Redis.User, | ||||||
| Password: cfg.Redis.Password, | ||||||
| DB: cfg.Redis.DB, | ||||||
| } | ||||||
|
|
||||||
| client := asynq.NewClient(redisOptions) | ||||||
| defer func() { | ||||||
| if err := client.Close(); err != nil { | ||||||
| fmt.Println("fail to close asynq client,", err) | ||||||
| } | ||||||
| }() | ||||||
|
|
||||||
| inspector := asynq.NewInspector(redisOptions) | ||||||
|
|
||||||
| vaultStorage, err := vault.NewBlockStorageImp(cfg.BlockStorage) | ||||||
| if err != nil { | ||||||
| panic(err) | ||||||
| } | ||||||
|
|
||||||
| db, err := postgres.NewPostgresBackend(cfg.Database.DSN, nil) | ||||||
| if err != nil { | ||||||
| logger.Fatalf("Failed to connect to database: %v", err) | ||||||
| } | ||||||
|
|
||||||
| txIndexerStore, err := tx_indexer_storage.NewPostgresTxIndexStore(ctx, cfg.Database.DSN) | ||||||
| if err != nil { | ||||||
| panic(fmt.Errorf("tx_indexer_storage.NewPostgresTxIndexStore: %w", err)) | ||||||
| } | ||||||
|
|
||||||
| txIndexerService := tx_indexer.NewService( | ||||||
| logger, | ||||||
| txIndexerStore, | ||||||
| tx_indexer.Chains(), | ||||||
| ) | ||||||
|
|
||||||
| ct, err := copytrader.NewPlugin( | ||||||
| db, | ||||||
| nil, // not used by server | ||||||
| vaultStorage, | ||||||
| nil, | ||||||
| txIndexerService, | ||||||
| client, | ||||||
| cfg.Server.EncryptionSecret, | ||||||
| ) | ||||||
| if err != nil { | ||||||
| logger.Fatalf("failed to create payroll plugin,err: %s", err) | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix incorrect error message referencing wrong plugin. The error message mentions "payroll plugin" instead of "copytrader plugin". - logger.Fatalf("failed to create payroll plugin,err: %s", err)
+ logger.Fatalf("failed to create copytrader plugin, err: %s", err)📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
| } | ||||||
|
|
||||||
| server := api.NewServer( | ||||||
| cfg.Server, | ||||||
| db, | ||||||
| redisStorage, | ||||||
| vaultStorage, | ||||||
| redisOptions, | ||||||
| client, | ||||||
| inspector, | ||||||
| sdClient, | ||||||
| ct, | ||||||
| ) | ||||||
| if err := server.StartServer(); err != nil { | ||||||
| panic(err) | ||||||
| } | ||||||
| } | ||||||
|
Comment on lines
+21
to
+102
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Consider adding graceful shutdown handling. The main function lacks graceful shutdown capabilities. Consider implementing signal handling to properly close connections and clean up resources on shutdown. +import (
+ "os"
+ "os/signal"
+ "syscall"
+)
func main() {
ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ // Setup signal handling
+ sigChan := make(chan os.Signal, 1)
+ signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
+ go func() {
+ <-sigChan
+ logger.Info("Shutdown signal received")
+ cancel()
+ }()
// ... existing initialization code ...
- if err := server.StartServer(); err != nil {
- panic(err)
+ go func() {
+ if err := server.StartServer(); err != nil {
+ logger.Fatalf("Server failed to start: %v", err)
+ }
}()
+
+ <-ctx.Done()
+ logger.Info("Shutting down server...")
}
🤖 Prompt for AI Agents |
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "os" | ||
| "strings" | ||
|
|
||
| "github.com/spf13/viper" | ||
| "github.com/vultisig/verifier/vault_config" | ||
|
|
||
| "github.com/vultisig/plugin/storage" | ||
| ) | ||
|
|
||
| type CopytraderWorkerConfig struct { | ||
| Redis storage.RedisConfig `mapstructure:"redis" json:"redis,omitempty"` | ||
| Rpc Rpc `mapstructure:"Rpc" json:"Rpc,omitempty"` | ||
| Verifier verifier `mapstructure:"verifier" json:"verifier,omitempty"` | ||
| BlockStorage vault_config.BlockStorage `mapstructure:"block_storage" json:"block_storage,omitempty"` | ||
| VaultServiceConfig vault_config.Config `mapstructure:"vault_service" json:"vault_service,omitempty"` | ||
| Datadog struct { | ||
| Host string `mapstructure:"host" json:"host,omitempty"` | ||
| Port string `mapstructure:"port" json:"port,omitempty"` | ||
| } `mapstructure:"datadog" json:"datadog"` | ||
| Database struct { | ||
| DSN string `mapstructure:"dsn" json:"dsn,omitempty"` | ||
| } `mapstructure:"database" json:"database,omitempty"` | ||
| } | ||
|
|
||
| type Rpc struct { | ||
| Ethereum rpcItem `mapstructure:"ethereum" json:"ethereum,omitempty"` | ||
| } | ||
|
|
||
| type rpcItem struct { | ||
| URL string `mapstructure:"url" json:"url,omitempty"` | ||
| } | ||
|
|
||
| type verifier struct { | ||
| URL string `mapstructure:"url"` | ||
| Token string `mapstructure:"token"` | ||
| PartyPrefix string `mapstructure:"party_prefix"` | ||
| } | ||
|
|
||
| func GetConfigure() (*CopytraderWorkerConfig, error) { | ||
| configName := os.Getenv("VS_CONFIG_NAME") | ||
| if configName == "" { | ||
| configName = "config" | ||
| } | ||
| return ReadConfig(configName) | ||
| } | ||
|
|
||
| func ReadConfig(configName string) (*CopytraderWorkerConfig, error) { | ||
| viper.SetConfigName(configName) | ||
| viper.AddConfigPath(".") | ||
| viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) | ||
| viper.AutomaticEnv() | ||
|
|
||
| if err := viper.ReadInConfig(); err != nil { | ||
| return nil, fmt.Errorf("fail to reading config file, %w", err) | ||
| } | ||
| var cfg CopytraderWorkerConfig | ||
| err := viper.Unmarshal(&cfg) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("unable to decode into struct, %w", err) | ||
| } | ||
| return &cfg, nil | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,124 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| package main | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "context" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "fmt" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "github.com/DataDog/datadog-go/statsd" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "github.com/ethereum/go-ethereum/ethclient" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "github.com/hibiken/asynq" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "github.com/sirupsen/logrus" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "github.com/vultisig/plugin/internal/keysign" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "github.com/vultisig/plugin/plugin/copytrader" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "github.com/vultisig/plugin/storage/postgres" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "github.com/vultisig/verifier/tx_indexer" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "github.com/vultisig/verifier/tx_indexer/pkg/storage" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "github.com/vultisig/verifier/vault" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "github.com/vultisig/vultiserver/relay" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "github.com/vultisig/plugin/internal/tasks" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Don't scale payroll.worker, it has scheduler which must be single instance running | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Consider moving scheduler to separate worker | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+22
to
+23
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix incorrect comment referencing payroll.worker The comment references "payroll.worker" but this is the copytrader worker. -// Don't scale payroll.worker, it has scheduler which must be single instance running
-// Consider moving scheduler to separate worker
+// Don't scale copytrader.worker if it has any singleton components
+// Consider architectural patterns for horizontal scaling if needed📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func main() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ctx := context.Background() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cfg, err := GetConfigure() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| panic(err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sdClient, err := statsd.New(cfg.Datadog.Host + ":" + cfg.Datadog.Port) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| panic(err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| vaultStorage, err := vault.NewBlockStorageImp(cfg.BlockStorage) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| panic(fmt.Sprintf("failed to initialize vault storage: %v", err)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| redisOptions := asynq.RedisClientOpt{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Addr: cfg.Redis.Host + ":" + cfg.Redis.Port, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Username: cfg.Redis.User, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Password: cfg.Redis.Password, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| DB: cfg.Redis.DB, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger := logrus.StandardLogger() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| client := asynq.NewClient(redisOptions) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| srv := asynq.NewServer( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| redisOptions, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| asynq.Config{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Logger: logger, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Concurrency: 10, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Queues: map[string]int{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| tasks.QUEUE_NAME: 10, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| txIndexerStore, err := storage.NewPostgresTxIndexStore(ctx, cfg.Database.DSN) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| panic(fmt.Errorf("storage.NewPostgresTxIndexStore: %w", err)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| txIndexerService := tx_indexer.NewService( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| txIndexerStore, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| tx_indexer.Chains(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| vaultService, err := vault.NewManagementService( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cfg.VaultServiceConfig, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| client, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sdClient, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| vaultStorage, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| txIndexerService, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| panic(fmt.Errorf("failed to create vault service: %w", err)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| postgressDB, err := postgres.NewPostgresBackend(cfg.Database.DSN, nil) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| panic(fmt.Errorf("failed to create postgres backend: %w", err)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rpcClient, err := ethclient.Dial(cfg.Rpc.Ethereum.URL) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| panic(fmt.Errorf("failed to create eth client: %w", err)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ct, err := copytrader.NewPlugin( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| postgressDB, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| keysign.NewSigner( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.WithField("pkg", "keysign.Signer").Logger, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| relay.NewRelayClient(cfg.VaultServiceConfig.Relay.Server), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| []keysign.Emitter{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| keysign.NewVerifierEmitter(cfg.Verifier.URL, cfg.Verifier.Token), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| keysign.NewPluginEmitter(client, tasks.TypeKeySignDKLS, tasks.QUEUE_NAME), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| []string{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cfg.Verifier.PartyPrefix, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cfg.VaultServiceConfig.LocalPartyPrefix, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| vaultStorage, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rpcClient, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| txIndexerService, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| client, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cfg.VaultServiceConfig.EncryptionSecret, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| panic(fmt.Errorf("failed to create copytrader plugin: %w", err)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mux := asynq.NewServeMux() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mux.HandleFunc(tasks.TypePluginTransaction, ct.HandleSwapTask) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mux.HandleFunc(tasks.TypeKeySignDKLS, vaultService.HandleKeySignDKLS) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mux.HandleFunc(tasks.TypeReshareDKLS, vaultService.HandleReshareDKLS) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err := srv.Run(mux); err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| panic(fmt.Errorf("could not run server: %w", err)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+117
to
+124
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add graceful shutdown handling The worker doesn't handle OS signals for graceful shutdown, which could lead to data loss or incomplete transactions. Replace the current server run with signal handling: + // Handle graceful shutdown
+ sigChan := make(chan os.Signal, 1)
+ signal.Notify(sigChan, syscall.SIGTERM, syscall.SIGINT)
+
+ go func() {
+ if err := srv.Run(mux); err != nil {
+ logger.Fatalf("could not run server: %v", err)
+ }
+ }()
+
+ <-sigChan
+ logger.Info("Shutting down worker...")
+
+ srv.Shutdown()
+ client.Close()
+
- if err := srv.Run(mux); err != nil {
- panic(fmt.Errorf("could not run server: %w", err))
- }Don't forget to import 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,6 @@ | ||||||||||||||||||||||
| package copytrader | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| const ( | ||||||||||||||||||||||
| UniswapV2RouterAddress = "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D" | ||||||||||||||||||||||
| SwapExactTokensForTokens = "38ed1739" | ||||||||||||||||||||||
| ) | ||||||||||||||||||||||
|
Comment on lines
+3
to
+6
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add network specificity and improve constant formatting The constants are hardcoded for Ethereum mainnet but lack network context. Additionally, the method ID should include the "0x" prefix for consistency with Ethereum conventions. Consider these improvements: const (
- UniswapV2RouterAddress = "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D"
- SwapExactTokensForTokens = "38ed1739"
+ // UniswapV2RouterAddress is the mainnet address for Uniswap V2 Router
+ UniswapV2RouterAddress = "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D"
+ // SwapExactTokensForTokens is the function selector for swapExactTokensForTokens(uint256,uint256,address[],address,uint256)
+ SwapExactTokensForTokens = "0x38ed1739"
)Additionally, consider creating a configuration or constants file that maps router addresses per network (mainnet, testnet, etc.) to avoid hardcoding network-specific values. 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Extract inline structs and consider sensitive data handling
The inline struct definitions for Database and Datadog reduce code reusability and maintainability. Also, the Database DSN may contain sensitive credentials.
Consider extracting these to separate types:
Also, ensure that sensitive configuration values like database DSN are properly secured (e.g., using environment variables or secret management systems).
📝 Committable suggestion
🤖 Prompt for AI Agents