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 }