|
| 1 | +package exchange |
| 2 | + |
| 3 | +import ( |
| 4 | + "context" |
| 5 | + "encoding/json" |
| 6 | + "fmt" |
| 7 | + "log/slog" |
| 8 | + |
| 9 | + oc "github.com/cordialsys/offchain" |
| 10 | + "github.com/cordialsys/offchain/cmd" |
| 11 | + "github.com/cordialsys/offchain/loader" |
| 12 | + "github.com/spf13/cobra" |
| 13 | +) |
| 14 | + |
| 15 | +func printJson(data interface{}) { |
| 16 | + bz, err := json.MarshalIndent(data, "", " ") |
| 17 | + if err != nil { |
| 18 | + panic(err) |
| 19 | + } |
| 20 | + fmt.Println(string(bz)) |
| 21 | +} |
| 22 | + |
| 23 | +type contextKey string |
| 24 | + |
| 25 | +const exchangeConfigKey contextKey = "exchange_config" |
| 26 | +const exchangeAccountSecretsKey contextKey = "exchange_account_secrets" |
| 27 | +const configContextKey contextKey = "config" |
| 28 | + |
| 29 | +func unwrapExchangeConfig(ctx context.Context) *oc.ExchangeConfig { |
| 30 | + return ctx.Value(exchangeConfigKey).(*oc.ExchangeConfig) |
| 31 | +} |
| 32 | + |
| 33 | +func unwrapAccountSecrets(ctx context.Context) *oc.MultiSecret { |
| 34 | + return ctx.Value(exchangeAccountSecretsKey).(*oc.MultiSecret) |
| 35 | +} |
| 36 | + |
| 37 | +func unwrapAccountConfig(ctx context.Context) (*oc.ExchangeConfig, *oc.MultiSecret) { |
| 38 | + exchangeConfig := unwrapExchangeConfig(ctx) |
| 39 | + secrets := unwrapAccountSecrets(ctx) |
| 40 | + return exchangeConfig, secrets |
| 41 | +} |
| 42 | + |
| 43 | +func NewExchangeCmd() *cobra.Command { |
| 44 | + var configPath string |
| 45 | + var exchange string |
| 46 | + var subaccountId string |
| 47 | + cmd := &cobra.Command{ |
| 48 | + Use: "exchange", |
| 49 | + Short: "Run commands on an exchange", |
| 50 | + Aliases: []string{"ex", "x", "exchanges"}, |
| 51 | + SilenceUsage: true, |
| 52 | + PersistentPreRunE: func(preCmd *cobra.Command, args []string) error { |
| 53 | + cmd.SetVerbosityFromCmd(preCmd) |
| 54 | + config, err := loader.LoadConfig(configPath) |
| 55 | + if err != nil { |
| 56 | + return err |
| 57 | + } |
| 58 | + ctx := preCmd.Context() |
| 59 | + |
| 60 | + if exchange == "" { |
| 61 | + return fmt.Errorf("--exchange is required") |
| 62 | + } |
| 63 | + exchangeConfig, ok := config.GetExchange(oc.ExchangeId(exchange)) |
| 64 | + if !ok { |
| 65 | + return fmt.Errorf("exchange not found. options are: %v", oc.ValidExchangeIds) |
| 66 | + } |
| 67 | + slog.Info("Using exchange", "exchange", exchange) |
| 68 | + ctx = context.WithValue(ctx, exchangeConfigKey, exchangeConfig) |
| 69 | + var secrets *oc.MultiSecret |
| 70 | + |
| 71 | + if subaccountId != "" { |
| 72 | + for _, subaccount := range exchangeConfig.SubAccounts { |
| 73 | + if subaccount.Id == subaccountId { |
| 74 | + secrets = &subaccount.MultiSecret |
| 75 | + } |
| 76 | + } |
| 77 | + if secrets == nil { |
| 78 | + return fmt.Errorf("subaccount %s not found in configuration for %s", subaccountId, exchange) |
| 79 | + } |
| 80 | + err = secrets.LoadSecrets() |
| 81 | + if err != nil { |
| 82 | + return fmt.Errorf("could not load secrets for %s subaccount %s: %w", exchange, subaccountId, err) |
| 83 | + } |
| 84 | + } else { |
| 85 | + secrets = &exchangeConfig.MultiSecret |
| 86 | + err = secrets.LoadSecrets() |
| 87 | + if err != nil { |
| 88 | + return fmt.Errorf("could not load secrets for %s: %w", exchange, err) |
| 89 | + } |
| 90 | + } |
| 91 | + |
| 92 | + ctx = context.WithValue(ctx, configContextKey, config) |
| 93 | + ctx = context.WithValue(ctx, exchangeAccountSecretsKey, secrets) |
| 94 | + preCmd.SetContext(ctx) |
| 95 | + |
| 96 | + return nil |
| 97 | + }, |
| 98 | + } |
| 99 | + cmd.AddCommand(NewGetAssetsCmd()) |
| 100 | + cmd.AddCommand(NewListBalancesCmd()) |
| 101 | + cmd.AddCommand(NewAccountTransferCmd()) |
| 102 | + cmd.AddCommand(NewWithdrawCmd()) |
| 103 | + cmd.AddCommand(NewGetDepositAddressCmd()) |
| 104 | + cmd.AddCommand(NewListWithdrawalHistoryCmd()) |
| 105 | + cmd.AddCommand(NewListSubaccountsCmd()) |
| 106 | + |
| 107 | + cmd.PersistentFlags().StringVarP( |
| 108 | + &exchange, |
| 109 | + "exchange", |
| 110 | + "x", |
| 111 | + "", |
| 112 | + fmt.Sprintf("The exchange to use (%v)", oc.ValidExchangeIds), |
| 113 | + ) |
| 114 | + |
| 115 | + cmd.PersistentFlags().StringVarP( |
| 116 | + &subaccountId, |
| 117 | + "subaccount", |
| 118 | + "s", |
| 119 | + "", |
| 120 | + "The subaccount to use. Defaults to using the main account.", |
| 121 | + ) |
| 122 | + |
| 123 | + cmd.PersistentFlags().StringVarP( |
| 124 | + &configPath, |
| 125 | + "config", |
| 126 | + "c", |
| 127 | + "", |
| 128 | + fmt.Sprintf("path to the config file (may set %s)", loader.ENV_OFFCHAIN_CONFIG), |
| 129 | + ) |
| 130 | + |
| 131 | + return cmd |
| 132 | +} |
0 commit comments