decred.org/dcrdex@v1.0.5/client/mm/libxc/binance_live_test.go (about)

     1  //go:build bnclive
     2  
     3  package libxc
     4  
     5  import (
     6  	"context"
     7  	"encoding/json"
     8  	"fmt"
     9  	"os"
    10  	"os/user"
    11  	"strings"
    12  	"sync"
    13  	"testing"
    14  	"time"
    15  
    16  	"decred.org/dcrdex/client/asset"
    17  	_ "decred.org/dcrdex/client/asset/importall"
    18  	"decred.org/dcrdex/client/mm/libxc/bntypes"
    19  	"decred.org/dcrdex/dex"
    20  )
    21  
    22  var (
    23  	log       = dex.StdOutLogger("T", dex.LevelTrace)
    24  	u, _      = user.Current()
    25  	apiKey    = ""
    26  	apiSecret = ""
    27  )
    28  
    29  func TestMain(m *testing.M) {
    30  	if s := os.Getenv("SECRET"); s != "" {
    31  		apiSecret = s
    32  	}
    33  	if k := os.Getenv("KEY"); k != "" {
    34  		apiKey = k
    35  	}
    36  
    37  	m.Run()
    38  }
    39  
    40  func tNewBinance(t *testing.T, net dex.Network) *binance {
    41  	cfg := &CEXConfig{
    42  		Net:       net,
    43  		APIKey:    apiKey,
    44  		SecretKey: apiSecret,
    45  		Logger:    log,
    46  		Notify: func(n interface{}) {
    47  			log.Infof("Notification sent: %+v", n)
    48  		},
    49  	}
    50  	const binanceUS = true
    51  	return newBinance(cfg, binanceUS)
    52  }
    53  
    54  type spoofDriver struct {
    55  	cFactor uint64
    56  }
    57  
    58  func (drv *spoofDriver) Open(*asset.WalletConfig, dex.Logger, dex.Network) (asset.Wallet, error) {
    59  	return nil, nil
    60  }
    61  
    62  func (drv *spoofDriver) DecodeCoinID(coinID []byte) (string, error) {
    63  	return "", nil
    64  }
    65  
    66  func (drv *spoofDriver) Info() *asset.WalletInfo {
    67  	return &asset.WalletInfo{
    68  		UnitInfo: dex.UnitInfo{
    69  			Conventional: dex.Denomination{
    70  				ConversionFactor: drv.cFactor,
    71  			},
    72  		},
    73  	}
    74  }
    75  
    76  func TestConnect(t *testing.T) {
    77  	bnc := tNewBinance(t, dex.Simnet)
    78  	ctx, cancel := context.WithTimeout(context.Background(), time.Hour*23)
    79  	defer cancel()
    80  
    81  	_, err := bnc.Connect(ctx)
    82  	if err != nil {
    83  		t.Fatalf("Connect error: %v", err)
    84  	}
    85  
    86  	balance, err := bnc.Balance(60)
    87  	if err != nil {
    88  		t.Fatalf("Balance error: %v", err)
    89  	}
    90  	t.Logf("usdc balance: %v", balance)
    91  
    92  	balance, err = bnc.Balance(0)
    93  	if err != nil {
    94  		t.Fatalf("Balance error: %v", err)
    95  	}
    96  	t.Logf("btc balance: %v", balance)
    97  }
    98  
    99  // This may fail due to balance being to low. You can try switching the side
   100  // of the trade or the qty.
   101  func TestTrade(t *testing.T) {
   102  	bnc := tNewBinance(t, dex.Testnet)
   103  	ctx, cancel := context.WithTimeout(context.Background(), time.Hour*23)
   104  	defer cancel()
   105  	_, err := bnc.Connect(ctx)
   106  	if err != nil {
   107  		t.Fatalf("Connect error: %v", err)
   108  	}
   109  
   110  	wg := sync.WaitGroup{}
   111  	wg.Add(1)
   112  	updates, unsubscribe, updaterID := bnc.SubscribeTradeUpdates()
   113  	defer unsubscribe()
   114  
   115  	go func() {
   116  		defer wg.Done()
   117  		for {
   118  			select {
   119  			case tradeUpdate := <-updates:
   120  				t.Logf("Trade Update: %+v", tradeUpdate)
   121  				if tradeUpdate.Complete {
   122  					// Sleep because context might get cancelled before
   123  					// Trade returns.
   124  					time.Sleep(1 * time.Second)
   125  					cancel()
   126  					return
   127  				}
   128  			case <-ctx.Done():
   129  				return
   130  			}
   131  		}
   132  	}()
   133  
   134  	trade, err := bnc.Trade(ctx, 60, 60001, false, 3600e5, 1e7, updaterID)
   135  	if err != nil {
   136  		t.Fatalf("trade error: %v", err)
   137  	}
   138  
   139  	if false { // Cancel the trade
   140  		time.Sleep(1 * time.Second)
   141  		err = bnc.CancelTrade(ctx, 60, 0, trade.ID)
   142  		if err != nil {
   143  			t.Fatalf("error cancelling trade: %v", err)
   144  		}
   145  	}
   146  
   147  	wg.Wait()
   148  }
   149  
   150  func TestCancelTrade(t *testing.T) {
   151  	tradeID := "42641326270691d752e000000001"
   152  
   153  	bnc := tNewBinance(t, dex.Testnet)
   154  	ctx, cancel := context.WithTimeout(context.Background(), time.Hour*23)
   155  	defer cancel()
   156  	_, err := bnc.Connect(ctx)
   157  	if err != nil {
   158  		t.Fatalf("Connect error: %v", err)
   159  	}
   160  
   161  	err = bnc.CancelTrade(ctx, 60, 0, tradeID)
   162  	if err != nil {
   163  		t.Fatalf("error cancelling trade: %v", err)
   164  	}
   165  }
   166  
   167  func TestMatchedMarkets(t *testing.T) {
   168  	bnc := tNewBinance(t, dex.Mainnet)
   169  	ctx, cancel := context.WithTimeout(context.Background(), time.Hour*23)
   170  	defer cancel()
   171  
   172  	_, err := bnc.Connect(ctx)
   173  	if err != nil {
   174  		t.Fatalf("Connect error: %v", err)
   175  	}
   176  
   177  	markets, err := bnc.Markets(ctx)
   178  	if err != nil {
   179  		t.Fatalf("failed to load markets")
   180  	}
   181  
   182  	for _, market := range markets {
   183  		fmt.Printf("%s_%s %d %d\n", dex.BipIDSymbol(market.BaseID), dex.BipIDSymbol(market.QuoteID), market.BaseMinWithdraw, market.QuoteMinWithdraw)
   184  	}
   185  }
   186  
   187  func TestVWAP(t *testing.T) {
   188  	bnc := tNewBinance(t, dex.Mainnet)
   189  	ctx, cancel := context.WithTimeout(context.Background(), time.Hour*23)
   190  	defer cancel()
   191  	_, err := bnc.Connect(ctx)
   192  	if err != nil {
   193  		t.Fatalf("Connect error: %v", err)
   194  	}
   195  
   196  	err = bnc.SubscribeMarket(ctx, 60, 60001)
   197  	if err != nil {
   198  		t.Fatalf("failed to subscribe to market: %v", err)
   199  	}
   200  
   201  	err = bnc.SubscribeMarket(ctx, 60, 0)
   202  	if err != nil {
   203  		t.Fatalf("failed to subscribe to market: %v", err)
   204  	}
   205  
   206  	time.Sleep(30 * time.Second)
   207  
   208  	avg, extrema, filled, err := bnc.VWAP(60, 0, true, 2e9)
   209  	if err != nil {
   210  		t.Fatalf("VWAP failed: %v", err)
   211  	}
   212  	t.Logf("ethbtc - avg: %v, extrema: %v, filled: %v", avg, extrema, filled)
   213  
   214  	avg, extrema, filled, err = bnc.VWAP(60, 60001, true, 2e9)
   215  	if err != nil {
   216  		t.Fatalf("VWAP failed: %v", err)
   217  	}
   218  	t.Logf("ethusdc - avg: %v, extrema: %v, filled: %v", avg, extrema, filled)
   219  
   220  	err = bnc.SubscribeMarket(ctx, 60, 0)
   221  	if err != nil {
   222  		t.Fatalf("failed to subscribe to market: %v", err)
   223  	}
   224  
   225  	avg, extrema, filled, err = bnc.VWAP(60, 0, true, 2e9)
   226  	if err != nil {
   227  		t.Fatalf("VWAP failed: %v", err)
   228  	}
   229  
   230  	t.Logf("ethbtc - avg: %v, extrema: %v, filled: %v", avg, extrema, filled)
   231  
   232  	bnc.UnsubscribeMarket(60, 0)
   233  
   234  	avg, extrema, filled, err = bnc.VWAP(60, 0, true, 2e9)
   235  	if err != nil {
   236  		t.Fatalf("VWAP failed: %v", err)
   237  	}
   238  
   239  	t.Logf("avg: %v, extrema: %v, filled: %v", avg, extrema, filled)
   240  
   241  	err = bnc.UnsubscribeMarket(60, 0)
   242  	if err != nil {
   243  		t.Fatalf("error unsubscribing market")
   244  	}
   245  
   246  	_, _, _, err = bnc.VWAP(60, 0, true, 2e9)
   247  	if err == nil {
   248  		t.Fatalf("error should be returned since all subscribers have unsubscribed")
   249  	}
   250  }
   251  
   252  func TestSubscribeMarket(t *testing.T) {
   253  	bnc := tNewBinance(t, dex.Testnet)
   254  	ctx, cancel := context.WithTimeout(context.Background(), time.Hour*23)
   255  	defer cancel()
   256  	wg, err := bnc.Connect(ctx)
   257  	if err != nil {
   258  		t.Fatalf("Connect error: %v", err)
   259  	}
   260  
   261  	err = bnc.SubscribeMarket(ctx, 60, 0)
   262  	if err != nil {
   263  		t.Fatalf("failed to subscribe to market: %v", err)
   264  	}
   265  
   266  	wg.Wait()
   267  }
   268  
   269  func TestWithdrawal(t *testing.T) {
   270  	bnc := tNewBinance(t, dex.Mainnet)
   271  	ctx, cancel := context.WithTimeout(context.Background(), time.Hour*23)
   272  	defer cancel()
   273  
   274  	_, err := bnc.Connect(ctx)
   275  	if err != nil {
   276  		t.Fatalf("Connect error: %v", err)
   277  	}
   278  
   279  	withdrawalID, err := bnc.Withdraw(ctx, 966, 2e10, "")
   280  	if err != nil {
   281  		fmt.Printf("withdrawal error: %v", err)
   282  		return
   283  	}
   284  
   285  	t.Logf("withdrawalID: %v", withdrawalID)
   286  }
   287  
   288  func TestConfirmDeposit(t *testing.T) {
   289  	bnc := tNewBinance(t, dex.Mainnet)
   290  	ctx, cancel := context.WithTimeout(context.Background(), time.Hour*23)
   291  	defer cancel()
   292  
   293  	_, err := bnc.Connect(ctx)
   294  	if err != nil {
   295  		t.Fatalf("Connect error: %v", err)
   296  	}
   297  
   298  	confirmed, amt := bnc.ConfirmDeposit(ctx, &DepositData{})
   299  	t.Logf("confirmed: %v, amt: %v", confirmed, amt)
   300  }
   301  
   302  func TestGetDepositAddress(t *testing.T) {
   303  	bnc := tNewBinance(t, dex.Mainnet)
   304  	ctx, cancel := context.WithTimeout(context.Background(), time.Hour*23)
   305  	defer cancel()
   306  
   307  	_, err := bnc.Connect(ctx)
   308  	if err != nil {
   309  		t.Fatalf("Connect error: %v", err)
   310  	}
   311  
   312  	addr, err := bnc.GetDepositAddress(ctx, 966)
   313  	if err != nil {
   314  		t.Fatalf("getDepositAddress error: %v", err)
   315  	}
   316  
   317  	t.Logf("deposit address: %v", addr)
   318  }
   319  
   320  func TestBalances(t *testing.T) {
   321  	bnc := tNewBinance(t, dex.Testnet)
   322  	ctx, cancel := context.WithTimeout(context.Background(), time.Hour*23)
   323  	defer cancel()
   324  
   325  	_, err := bnc.Connect(ctx)
   326  	if err != nil {
   327  		t.Fatalf("Connect error: %v", err)
   328  	}
   329  
   330  	balance, err := bnc.Balance(0)
   331  	if err != nil {
   332  		t.Fatalf("balances error: %v", err)
   333  	}
   334  
   335  	t.Logf("%+v", balance)
   336  }
   337  
   338  func TestGetCoinInfo(t *testing.T) {
   339  	bnc := tNewBinance(t, dex.Mainnet)
   340  	ctx, cancel := context.WithTimeout(context.Background(), time.Hour*23)
   341  	defer cancel()
   342  
   343  	coins := make([]*bntypes.CoinInfo, 0)
   344  	err := bnc.getAPI(ctx, "/sapi/v1/capital/config/getall", nil, true, true, &coins)
   345  	if err != nil {
   346  		t.Fatalf("error getting binance coin info: %v", err)
   347  	}
   348  
   349  	coinLookup := make(map[string]bool)
   350  	for _, a := range asset.Assets() {
   351  		coinLookup[a.Info.UnitInfo.Conventional.Unit] = true
   352  		for _, tkn := range a.Tokens {
   353  			coinLookup[tkn.UnitInfo.Conventional.Unit] = true
   354  		}
   355  	}
   356  
   357  	for _, c := range coins {
   358  		if !coinLookup[c.Coin] {
   359  			continue
   360  		}
   361  		networkMins := make([]string, 0)
   362  		for _, n := range c.NetworkList {
   363  			if !n.DepositEnable || !n.WithdrawEnable {
   364  				fmt.Printf("%s on network %s not withdrawing and/or depositing. withdraw = %t, deposit = %t\n",
   365  					c.Coin, n.Network, n.WithdrawEnable, n.DepositEnable)
   366  			}
   367  			networkMins = append(networkMins, fmt.Sprintf("{net: %s, min_withdraw: %.8f, withdraw_fee: %.8f}", n.Network, n.WithdrawMin, n.WithdrawFee))
   368  		}
   369  		fmt.Printf("%q network mins: %+v \n", c.Coin, strings.Join(networkMins, ", "))
   370  	}
   371  }
   372  
   373  func TestTradeStatus(t *testing.T) {
   374  	bnc := tNewBinance(t, dex.Testnet)
   375  	ctx, cancel := context.WithTimeout(context.Background(), time.Hour*23)
   376  	defer cancel()
   377  
   378  	_, err := bnc.Connect(ctx)
   379  	if err != nil {
   380  		t.Fatalf("Connect error: %v", err)
   381  	}
   382  
   383  	trade, err := bnc.TradeStatus(ctx, "eb6b6e1177213643142700000001", 60, 60001)
   384  	if err != nil {
   385  		t.Fatalf("trade status error: %v", err)
   386  	}
   387  
   388  	t.Logf("trade status: %+v", trade)
   389  }
   390  
   391  func TestMarkets(t *testing.T) {
   392  	// Need keys for getCoinInfo
   393  	bnc := tNewBinance(t, dex.Testnet)
   394  	ctx, cancel := context.WithTimeout(context.Background(), time.Hour*23)
   395  	defer cancel()
   396  
   397  	err := bnc.getCoinInfo(ctx)
   398  	if err != nil {
   399  		t.Fatalf("error getting coin info: %v", err)
   400  	}
   401  
   402  	mkts, err := bnc.Markets(ctx)
   403  	if err != nil {
   404  		t.Fatalf("error getting markets: %v", err)
   405  	}
   406  
   407  	b, _ := json.MarshalIndent(mkts, "", "    ")
   408  	fmt.Println("##### Market Data:", string(b))
   409  }