decred.org/dcrdex@v1.0.5/server/asset/driver.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 asset 5 6 import ( 7 "fmt" 8 9 "decred.org/dcrdex/dex" 10 ) 11 12 var ( 13 drivers = make(map[uint32]Driver) 14 tokens = make(map[uint32]TokenDriver) 15 childTokens = make(map[uint32]map[uint32]*dex.Token) 16 ) 17 18 // driverBase defines a base set of driver methods common to both base-chain and 19 // degenerate assets. 20 type driverBase interface { 21 DecodeCoinID(coinID []byte) (string, error) 22 // Version returns the Backend's version number, which is used to signal 23 // when major changes are made to internal details such as coin ID encoding 24 // and contract structure that must be common to a client's. 25 Version() uint32 26 // UnitInfo returns the dex.UnitInfo for the asset. 27 UnitInfo() dex.UnitInfo 28 // Name is the name for the asset. 29 Name() string 30 } 31 32 // minValuer can be implemented by assets with minimum dust sizes that vary 33 // with fee rate. If an asset driver does not implement minValuer, the min 34 // value is assumed to be 1 atom for both bond and lot sizes. 35 type minValuer interface { 36 MinBondSize(maxFeeRate uint64) uint64 37 MinLotSize(maxFeeRate uint64) uint64 38 } 39 40 // Driver is the interface required of all base chain assets. 41 type Driver interface { 42 driverBase 43 // Setup should create a Backend, but not start the backend connection. 44 Setup(*BackendConfig) (Backend, error) 45 } 46 47 // TokenDriver is the interface required of all token assets. 48 type TokenDriver interface { 49 driverBase 50 TokenInfo() *dex.Token 51 } 52 53 func baseDriver(assetID uint32) (driverBase, bool) { 54 if drv, found := drivers[assetID]; found { 55 return drv, true 56 } 57 if drv, found := tokens[assetID]; found { 58 return drv, true 59 } 60 return nil, false 61 } 62 63 // DecodeCoinID creates a human-readable representation of a coin ID for a named 64 // asset with a corresponding driver registered with this package. 65 func DecodeCoinID(assetID uint32, coinID []byte) (string, error) { 66 drv, ok := baseDriver(assetID) 67 if !ok { 68 return "", fmt.Errorf("unknown asset driver %d", assetID) 69 } 70 return drv.DecodeCoinID(coinID) 71 } 72 73 // asset with a corresponding driver registered with this package. 74 func UnitInfo(assetID uint32) (dex.UnitInfo, error) { 75 drv, ok := baseDriver(assetID) 76 if !ok { 77 return dex.UnitInfo{}, fmt.Errorf("unknown asset %d (%q) in UnitInfo", assetID, dex.BipIDSymbol(assetID)) 78 } 79 return drv.UnitInfo(), nil 80 81 } 82 83 // Register should be called by the init function of an asset's package. 84 func Register(assetID uint32, drv Driver) { 85 if drv == nil { 86 panic("asset: Register driver is nil") 87 } 88 if _, ok := baseDriver(assetID); ok { 89 panic(fmt.Sprintf("asset: Register called twice for asset driver %d", assetID)) 90 } 91 if drv.UnitInfo().Conventional.ConversionFactor == 0 { 92 panic(fmt.Sprintf("asset: Driver registered with unit conversion factor = 0: %q", assetID)) 93 } 94 drivers[assetID] = drv 95 } 96 97 // RegisterToken is called to register a token. The parent asset should be 98 // registered first. 99 func RegisterToken(assetID uint32, drv TokenDriver) { 100 if drv == nil { 101 panic("asset: Register driver is nil") 102 } 103 if _, ok := tokens[assetID]; ok { 104 panic(fmt.Sprintf("asset: RegisterToken called twice for asset driver %d", assetID)) 105 } 106 token := drv.TokenInfo() 107 if token == nil { 108 panic(fmt.Sprintf("nil *Token for asset %d", assetID)) 109 } 110 if _, exists := drivers[token.ParentID]; !exists { 111 panic(fmt.Sprintf("no parent (%d) registered for %s", token.ParentID, token.Name)) 112 } 113 if drv.UnitInfo().Conventional.ConversionFactor == 0 { 114 panic(fmt.Sprintf("asset: TokenDriver registered with unit conversion factor = 0: %q", assetID)) 115 } 116 children := childTokens[token.ParentID] 117 if children == nil { 118 children = make(map[uint32]*dex.Token, 1) 119 childTokens[token.ParentID] = children 120 } 121 children[assetID] = token 122 tokens[assetID] = drv 123 } 124 125 type BackendConfig struct { 126 AssetID uint32 127 ConfigPath string 128 Logger dex.Logger 129 Net dex.Network 130 RelayAddr string 131 } 132 133 // Setup sets up the named asset. The RPC connection parameters are obtained 134 // from the asset's configuration file located at configPath. Setup is only 135 // called for base chain assets, not tokens. 136 func Setup(cfg *BackendConfig) (Backend, error) { 137 drv, ok := drivers[cfg.AssetID] 138 if !ok { 139 return nil, fmt.Errorf("asset: unknown asset driver %d", cfg.AssetID) 140 } 141 return drv.Setup(cfg) 142 } 143 144 // Version retrieves the version of the named asset's Backend implementation. 145 func Version(assetID uint32) (uint32, error) { 146 drv, ok := baseDriver(assetID) 147 if !ok { 148 return 0, fmt.Errorf("asset: unknown asset driver %d", assetID) 149 } 150 return drv.Version(), nil 151 } 152 153 // IsToken checks if the asset ID is for a token and returns the token's parent 154 // ID. 155 func IsToken(assetID uint32) (is bool, parentID uint32) { 156 token, is := tokens[assetID] 157 if !is { 158 return 159 } 160 return true, token.TokenInfo().ParentID 161 } 162 163 // Tokens returns the child tokens registered for a base chain asset. 164 func Tokens(assetID uint32) map[uint32]*dex.Token { 165 m := make(map[uint32]*dex.Token, len(childTokens[assetID])) 166 for k, v := range childTokens[assetID] { 167 m[k] = v 168 } 169 return m 170 } 171 172 // Minimums returns the minimimum lot size and bond size for a registered asset. 173 func Minimums(assetID uint32, maxFeeRate uint64) (minLotSize, minBondSize uint64, found bool) { 174 baseChainID := assetID 175 if token, is := tokens[assetID]; is { 176 baseChainID = token.TokenInfo().ParentID 177 } 178 drv, found := drivers[baseChainID] 179 if !found { 180 return 0, 0, false 181 } 182 m, is := drv.(minValuer) 183 if !is { 184 return 1, 1, true 185 } 186 return m.MinLotSize(maxFeeRate), m.MinBondSize(maxFeeRate), true 187 } 188 189 // RegisteredAsset is information about a registered asset. 190 type RegisteredAsset struct { 191 AssetID uint32 192 Symbol string 193 Name string 194 UnitInfo dex.UnitInfo 195 } 196 197 // Assets returns a information about registered assets. 198 func Assets() []*RegisteredAsset { 199 assets := make([]*RegisteredAsset, 0, len(drivers)+len(tokens)) 200 for assetID, drv := range drivers { 201 assets = append(assets, &RegisteredAsset{ 202 AssetID: assetID, 203 Symbol: dex.BipIDSymbol(assetID), 204 Name: drv.Name(), 205 UnitInfo: drv.UnitInfo(), 206 }) 207 } 208 for assetID, drv := range tokens { 209 assets = append(assets, &RegisteredAsset{ 210 AssetID: assetID, 211 Symbol: dex.BipIDSymbol(assetID), 212 Name: drv.Name(), 213 UnitInfo: drv.UnitInfo(), 214 }) 215 } 216 return assets 217 }