decred.org/dcrdex@v1.0.5/server/asset/bch/bch.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 bch
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"decred.org/dcrdex/dex"
    10  	dexbch "decred.org/dcrdex/dex/networks/bch"
    11  	dexbtc "decred.org/dcrdex/dex/networks/btc"
    12  	"decred.org/dcrdex/server/asset"
    13  	"decred.org/dcrdex/server/asset/btc"
    14  	"github.com/btcsuite/btcd/chaincfg"
    15  )
    16  
    17  var maxFeeBlocks = 3
    18  
    19  // Driver implements asset.Driver.
    20  type Driver struct{}
    21  
    22  // Setup creates the BCH backend. Start the backend with its Run method.
    23  func (d *Driver) Setup(cfg *asset.BackendConfig) (asset.Backend, error) {
    24  	return NewBackend(cfg)
    25  }
    26  
    27  // Version returns the Backend implementation's version number.
    28  func (d *Driver) Version() uint32 {
    29  	return version
    30  }
    31  
    32  // DecodeCoinID creates a human-readable representation of a coin ID for
    33  // Bitcoin Cash.
    34  func (d *Driver) DecodeCoinID(coinID []byte) (string, error) {
    35  	// Bitcoin Cash and Bitcoin have the same tx hash and output format.
    36  	return (&btc.Driver{}).DecodeCoinID(coinID)
    37  }
    38  
    39  // UnitInfo returns the dex.UnitInfo for the asset.
    40  func (d *Driver) UnitInfo() dex.UnitInfo {
    41  	return dexbch.UnitInfo
    42  }
    43  
    44  // MinBondSize calculates the minimum bond size for a given fee rate that avoids
    45  // dust outputs on the bond and refund txs, assuming the maxFeeRate doesn't
    46  // change.
    47  func (d *Driver) MinBondSize(maxFeeRate uint64) uint64 {
    48  	return dexbtc.MinBondSize(maxFeeRate, false)
    49  }
    50  
    51  // MinLotSize calculates the minimum bond size for a given fee rate that avoids
    52  // dust outputs on the swap and refund txs, assuming the maxFeeRate doesn't
    53  // change.
    54  func (d *Driver) MinLotSize(maxFeeRate uint64) uint64 {
    55  	return dexbtc.MinLotSize(maxFeeRate, false)
    56  }
    57  
    58  // Name is the asset's name.
    59  func (d *Driver) Name() string {
    60  	return "Bitcoin Cash"
    61  }
    62  
    63  func init() {
    64  	asset.Register(BipID, &Driver{})
    65  }
    66  
    67  const (
    68  	version   = 0
    69  	BipID     = 145
    70  	assetName = "bch"
    71  )
    72  
    73  // NewBackend generates the network parameters and creates a bch backend as a
    74  // btc clone using an asset/btc helper function.
    75  func NewBackend(cfg *asset.BackendConfig) (asset.Backend, error) {
    76  	var params *chaincfg.Params
    77  	switch cfg.Net {
    78  	case dex.Mainnet:
    79  		params = dexbch.MainNetParams
    80  	case dex.Testnet:
    81  		params = dexbch.TestNet4Params
    82  	case dex.Regtest:
    83  		params = dexbch.RegressionNetParams
    84  	default:
    85  		return nil, fmt.Errorf("unknown network ID %v", cfg.Net)
    86  	}
    87  
    88  	// Designate the clone ports. These will be overwritten by any explicit
    89  	// settings in the configuration file. Bitcoin Cash uses the same default
    90  	// ports as Bitcoin.
    91  	ports := dexbtc.NetPorts{
    92  		Mainnet: "8332",
    93  		Testnet: "28332",
    94  		Simnet:  "18443",
    95  	}
    96  
    97  	configPath := cfg.ConfigPath
    98  	if configPath == "" {
    99  		configPath = dexbtc.SystemConfigPath("bitcoin") // Yes, Bitcoin Cash's default config path is the same as bitcoin.
   100  	}
   101  
   102  	be, err := btc.NewBTCClone(&btc.BackendCloneConfig{
   103  		Name:             assetName,
   104  		Segwit:           false,
   105  		ConfigPath:       configPath,
   106  		AddressDecoder:   dexbch.DecodeCashAddress,
   107  		Logger:           cfg.Logger,
   108  		Net:              cfg.Net,
   109  		ChainParams:      params,
   110  		Ports:            ports,
   111  		DumbFeeEstimates: true,
   112  		// Bitcoin cash actually has getblockstats, but the RPC returns floats
   113  		// in units of BCH/byte.
   114  		ManualMedianFee:      true,
   115  		NoCompetitionFeeRate: 2,
   116  		MaxFeeBlocks:         maxFeeBlocks,
   117  		ArglessFeeEstimates:  true,
   118  		RelayAddr:            cfg.RelayAddr,
   119  	})
   120  	if err != nil {
   121  		return nil, err
   122  	}
   123  
   124  	return &BCHBackend{
   125  		Backend: be,
   126  	}, nil
   127  }
   128  
   129  // BCHBackend embeds *btc.Backend and re-implements the Contract method to deal
   130  // with Cash Address translation.
   131  type BCHBackend struct {
   132  	*btc.Backend
   133  }
   134  
   135  // Contract returns the output from embedded Backend's Contract method, but
   136  // with the SwapAddress field converted to Cash Address encoding.
   137  func (bch *BCHBackend) Contract(coinID []byte, redeemScript []byte) (*asset.Contract, error) { // Contract.SwapAddress
   138  	contract, err := bch.Backend.Contract(coinID, redeemScript)
   139  	if err != nil {
   140  		return nil, err
   141  	}
   142  	contract.SwapAddress, err = dexbch.RecodeCashAddress(contract.SwapAddress, bch.Net())
   143  	if err != nil {
   144  		return nil, err
   145  	}
   146  	return contract, nil
   147  }