decred.org/dcrdex@v1.0.5/client/asset/eth/cmd/getgas/main.go (about)

     1  // This code is available on the terms of the project LICENSE.md file,
     2  // also available online at https://blueoakcouncil.org/license/1.0.0.
     3  
     4  package main
     5  
     6  import (
     7  	"context"
     8  	"flag"
     9  	"fmt"
    10  	"os"
    11  	"os/user"
    12  	"path/filepath"
    13  	"strings"
    14  
    15  	"decred.org/dcrdex/client/asset/eth"
    16  	"decred.org/dcrdex/client/asset/polygon"
    17  	"decred.org/dcrdex/dex"
    18  	dexeth "decred.org/dcrdex/dex/networks/eth"
    19  	dexpolygon "decred.org/dcrdex/dex/networks/polygon"
    20  	"github.com/ethereum/go-ethereum/common"
    21  	"github.com/ethereum/go-ethereum/params"
    22  )
    23  
    24  func main() {
    25  	if err := mainErr(); err != nil {
    26  		fmt.Fprint(os.Stderr, err, "\n")
    27  		os.Exit(1)
    28  	}
    29  	os.Exit(0)
    30  }
    31  
    32  func mainErr() error {
    33  	ctx, cancel := context.WithCancel(context.Background())
    34  	defer cancel()
    35  
    36  	u, err := user.Current()
    37  	if err != nil {
    38  		return fmt.Errorf("could not get the current user: %w", err)
    39  	}
    40  	defaultCredentialsPath := filepath.Join(u.HomeDir, "dextest", "credentials.json")
    41  
    42  	var maxSwaps, contractVerI int
    43  	var chain, token, credentialsPath, returnAddr string
    44  	var useTestnet, useMainnet, useSimnet, trace, debug, readCreds, fundingReq bool
    45  	flag.BoolVar(&readCreds, "readcreds", false, "does not run gas estimates. read the credentials file and print the address")
    46  	flag.BoolVar(&fundingReq, "fundingrequired", false, "does not run gas estimates. calculate the funding required by the wallet to get estimates")
    47  	flag.StringVar(&returnAddr, "return", "", "does not run gas estimates. return ethereum funds to supplied address")
    48  	flag.BoolVar(&useMainnet, "mainnet", false, "use mainnet")
    49  	flag.BoolVar(&useTestnet, "testnet", false, "use testnet")
    50  	flag.BoolVar(&useSimnet, "simnet", false, "use simnet")
    51  	flag.BoolVar(&trace, "trace", false, "use simnet")
    52  	flag.BoolVar(&debug, "debug", false, "use simnet")
    53  	flag.IntVar(&maxSwaps, "n", 5, "max number of swaps per transaction. minimum is 2. test will run from 2 swap up to n swaps.")
    54  	flag.StringVar(&chain, "chain", "eth", "symbol of the base chain")
    55  	flag.StringVar(&token, "token", "", "symbol of the token. if token is not specified, will check gas for base chain")
    56  	flag.IntVar(&contractVerI, "ver", 0, "contract version")
    57  	flag.StringVar(&credentialsPath, "creds", defaultCredentialsPath, "path for JSON credentials file.")
    58  	flag.Parse()
    59  
    60  	if !useMainnet && !useTestnet && !useSimnet {
    61  		return fmt.Errorf("no network specified. add flag --mainnet, --testnet, or --simnet")
    62  	}
    63  	if (useMainnet && useTestnet) || (useMainnet && useSimnet) || (useTestnet && useSimnet) {
    64  		return fmt.Errorf("more than one network specified")
    65  	}
    66  
    67  	net := dex.Mainnet
    68  	if useSimnet {
    69  		net = dex.Simnet
    70  		dexeth.MaybeReadSimnetAddrs()
    71  		dexpolygon.MaybeReadSimnetAddrs()
    72  	}
    73  	if useTestnet {
    74  		net = dex.Testnet
    75  	}
    76  
    77  	if readCreds {
    78  		addr, providers, err := eth.GetGas.ReadCredentials(chain, credentialsPath, net)
    79  		if err != nil {
    80  			return err
    81  		}
    82  		fmt.Println("Credentials successfully parsed")
    83  		fmt.Println("Address:", addr)
    84  		fmt.Println("Providers:", strings.Join(providers, ", "))
    85  		return nil
    86  	}
    87  
    88  	if maxSwaps < 2 {
    89  		return fmt.Errorf("n cannot be < 2")
    90  	}
    91  
    92  	if token == "" {
    93  		token = chain
    94  	}
    95  
    96  	// Allow specification of tokens without .[chain] suffix.
    97  	if chain != token && !strings.Contains(token, ".") {
    98  		token = token + "." + chain
    99  	}
   100  
   101  	assetID, found := dex.BipSymbolID(token)
   102  	if !found {
   103  		return fmt.Errorf("asset %s not known", token)
   104  	}
   105  	contractVer := uint32(contractVerI)
   106  
   107  	logLvl := dex.LevelInfo
   108  	if debug {
   109  		logLvl = dex.LevelDebug
   110  	}
   111  	if trace {
   112  		logLvl = dex.LevelTrace
   113  	}
   114  
   115  	log := dex.StdOutLogger("GG", logLvl)
   116  
   117  	walletParams := func(
   118  		gases map[uint32]*dexeth.Gases,
   119  		contracts map[uint32]map[dex.Network]common.Address,
   120  		tokens map[uint32]*dexeth.Token,
   121  		compatLookup func(net dex.Network) (c eth.CompatibilityData, err error),
   122  		chainCfg func(net dex.Network) (c *params.ChainConfig, err error),
   123  		bui *dex.UnitInfo,
   124  	) (*eth.GetGasWalletParams, error) {
   125  
   126  		wParams := new(eth.GetGasWalletParams)
   127  		wParams.BaseUnitInfo = bui
   128  		if token != chain {
   129  			var exists bool
   130  			tkn, exists := tokens[assetID]
   131  			if !exists {
   132  				return nil, fmt.Errorf("specified token %s does not exist on base chain %s", token, chain)
   133  			}
   134  			wParams.Token = tkn
   135  			wParams.UnitInfo = &tkn.UnitInfo
   136  			netToken, exists := tkn.NetTokens[net]
   137  			if !exists {
   138  				return nil, fmt.Errorf("no %s token on %s network %s", tkn.Name, chain, net)
   139  			}
   140  			swapContract, exists := netToken.SwapContracts[contractVer]
   141  			if !exists {
   142  				return nil, fmt.Errorf("no verion %d contract for %s token on %s network %s", contractVer, tkn.Name, chain, net)
   143  			}
   144  			wParams.Gas = &swapContract.Gas
   145  		} else {
   146  			wParams.UnitInfo = bui
   147  			g, exists := gases[contractVer]
   148  			if !exists {
   149  				return nil, fmt.Errorf("no verion %d contract for %s network %s", contractVer, chain, net)
   150  			}
   151  			wParams.Gas = g
   152  			cs, exists := contracts[contractVer]
   153  			if !exists {
   154  				return nil, fmt.Errorf("no version %d base chain swap contract on %s", contractVer, chain)
   155  			}
   156  			wParams.ContractAddr, exists = cs[net]
   157  			if !exists {
   158  				return nil, fmt.Errorf("no version %d base chain swap contract on %s network %s", contractVer, chain, net)
   159  			}
   160  		}
   161  		wParams.ChainCfg, err = chainCfg(net)
   162  		if err != nil {
   163  			return nil, fmt.Errorf("error finding chain config: %v", err)
   164  		}
   165  		compat, err := compatLookup(net)
   166  		if err != nil {
   167  			return nil, fmt.Errorf("error finding api compatibility data: %v", err)
   168  		}
   169  		wParams.Compat = &compat
   170  		return wParams, nil
   171  	}
   172  
   173  	var wParams *eth.GetGasWalletParams
   174  	switch chain {
   175  	case "eth":
   176  		wParams, err = walletParams(dexeth.VersionedGases, dexeth.ContractAddresses, dexeth.Tokens,
   177  			eth.NetworkCompatibilityData, eth.ChainConfig, &dexeth.UnitInfo)
   178  	case "polygon":
   179  		wParams, err = walletParams(dexpolygon.VersionedGases, dexpolygon.ContractAddresses, dexpolygon.Tokens,
   180  			polygon.NetworkCompatibilityData, polygon.ChainConfig, &dexpolygon.UnitInfo)
   181  	default:
   182  		return fmt.Errorf("chain %s not known", chain)
   183  	}
   184  	if err != nil {
   185  		return fmt.Errorf("error generating wallet params: %w", err)
   186  	}
   187  
   188  	switch {
   189  	case fundingReq:
   190  		return eth.GetGas.EstimateFunding(ctx, net, assetID, contractVer, maxSwaps, credentialsPath, wParams, log)
   191  	case returnAddr != "":
   192  		return eth.GetGas.Return(ctx, assetID, credentialsPath, returnAddr, wParams, net, log)
   193  	default:
   194  		return eth.GetGas.Estimate(ctx, net, assetID, contractVer, maxSwaps, credentialsPath, wParams, log)
   195  	}
   196  }