decred.org/dcrdex@v1.0.5/client/asset/dcr/wallet.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 dcr 5 6 import ( 7 "context" 8 "fmt" 9 10 "decred.org/dcrdex/client/asset" 11 "decred.org/dcrdex/dex" 12 walletjson "decred.org/dcrwallet/v5/rpc/jsonrpc/types" 13 "decred.org/dcrwallet/v5/wallet" 14 "github.com/decred/dcrd/chaincfg/chainhash" 15 "github.com/decred/dcrd/chaincfg/v3" 16 "github.com/decred/dcrd/dcrec/secp256k1/v4" 17 "github.com/decred/dcrd/dcrutil/v4" 18 chainjson "github.com/decred/dcrd/rpc/jsonrpc/types/v4" 19 "github.com/decred/dcrd/txscript/v4/stdaddr" 20 "github.com/decred/dcrd/wire" 21 ) 22 23 // WalletConstructor defines a function that can be invoked to create a custom 24 // implementation of the Wallet interface. 25 type WalletConstructor func(settings map[string]string, chainParams *chaincfg.Params, logger dex.Logger) (Wallet, error) 26 27 // customWalletConstructors are functions for setting up custom implementations 28 // of the Wallet interface that may be used by the ExchangeWallet instead of the 29 // default rpcWallet implementation. 30 var customWalletConstructors = map[string]WalletConstructor{} 31 32 // RegisterCustomWallet registers a function that should be used in creating a 33 // Wallet implementation that the ExchangeWallet of the specified type will use 34 // in place of the default rpcWallet implementation. External consumers can use 35 // this function to provide alternative Wallet implementations, and must do so 36 // before attempting to create an ExchangeWallet instance of this type. It'll 37 // panic if callers try to register a wallet twice. 38 func RegisterCustomWallet(constructor WalletConstructor, def *asset.WalletDefinition) { 39 for _, availableWallets := range WalletInfo.AvailableWallets { 40 if def.Type == availableWallets.Type { 41 panic(fmt.Sprintf("wallet type (%q) already registered", def.Type)) 42 } 43 } 44 customWalletConstructors[def.Type] = constructor 45 WalletInfo.AvailableWallets = append(WalletInfo.AvailableWallets, def) 46 } 47 48 type TipChangeCallback func(context.Context, *chainhash.Hash, int64, error) 49 50 // BlockHeader is a wire.BlockHeader with the addition of a MedianTime field. 51 // Implementations must fill in the MedianTime field when returning a 52 // BlockHeader. 53 type BlockHeader struct { 54 *wire.BlockHeader 55 MedianTime int64 56 Confirmations int64 57 NextHash *chainhash.Hash 58 } 59 60 // AddressInfo is the source account and branch info for an address. 61 type AddressInfo struct { 62 Account string 63 Branch uint32 64 } 65 66 type XCWalletAccounts struct { 67 PrimaryAccount string 68 UnmixedAccount string 69 TradingAccount string 70 } 71 72 // ListTransactionsResult is similar to the walletjson.ListTransactionsResult, 73 // but most fields omitted. 74 type ListTransactionsResult struct { 75 TxID string 76 BlockIndex *int64 77 BlockTime int64 78 // Send set to true means that the inputs of the transaction were 79 // controlled by the wallet. 80 Send bool `json:"send"` 81 Fee *float64 82 TxType *walletjson.ListTransactionsTxType 83 } 84 85 // Wallet defines methods that the ExchangeWallet uses for communicating with 86 // a Decred wallet and blockchain. 87 type Wallet interface { 88 // Connect establishes a connection to the wallet. 89 Connect(ctx context.Context) error 90 // Disconnect shuts down access to the wallet. 91 Disconnect() 92 // SpvMode returns true if the wallet is connected to the Decred 93 // network via SPV peers. 94 SpvMode() bool 95 // Accounts returns the names of the accounts for use by the exchange 96 // wallet. 97 Accounts() XCWalletAccounts 98 // AddressInfo returns information for the provided address. It is an error 99 // if the address is not owned by the wallet. 100 AddressInfo(ctx context.Context, address string) (*AddressInfo, error) 101 // AccountOwnsAddress checks if the provided address belongs to the 102 // specified account. 103 AccountOwnsAddress(ctx context.Context, addr stdaddr.Address, acctName string) (bool, error) 104 // AccountBalance returns the balance breakdown for the specified account. 105 AccountBalance(ctx context.Context, confirms int32, acctName string) (*walletjson.GetAccountBalanceResult, error) 106 // LockedOutputs fetches locked outputs for the Wallet. 107 LockedOutputs(ctx context.Context, acctName string) ([]chainjson.TransactionInput, error) 108 // Unspents fetches unspent outputs for the Wallet. 109 Unspents(ctx context.Context, acctName string) ([]*walletjson.ListUnspentResult, error) 110 // LockUnspent locks or unlocks the specified outpoint. 111 LockUnspent(ctx context.Context, unlock bool, ops []*wire.OutPoint) error 112 // UnspentOutput returns information about an unspent tx output, if found 113 // and unspent. Use wire.TxTreeUnknown if the output tree is unknown, the 114 // correct tree will be returned if the unspent output is found. 115 // This method is only guaranteed to return results for outputs that pay to 116 // the wallet, although wallets connected to a full node may return results 117 // for non-wallet outputs. Returns asset.CoinNotFoundError if the unspent 118 // output cannot be located. 119 UnspentOutput(ctx context.Context, txHash *chainhash.Hash, index uint32, tree int8) (*TxOutput, error) 120 // ExternalAddress returns a new external address. 121 ExternalAddress(ctx context.Context, acctName string) (stdaddr.Address, error) 122 // InternalAddress returns a change address from the Wallet. 123 InternalAddress(ctx context.Context, acctName string) (stdaddr.Address, error) 124 // SignRawTransaction signs the provided transaction. SignRawTransaction 125 // is not used for redemptions, so previous outpoints and scripts should 126 // be known by the wallet. 127 // SignRawTransaction should not mutate the input transaction. 128 SignRawTransaction(context.Context, *wire.MsgTx) (*wire.MsgTx, error) 129 // SendRawTransaction broadcasts the provided transaction to the Decred 130 // network. 131 SendRawTransaction(ctx context.Context, tx *wire.MsgTx, allowHighFees bool) (*chainhash.Hash, error) 132 // GetBlockHeader generates a *BlockHeader for the specified block hash. The 133 // returned block header is a wire.BlockHeader with the addition of the 134 // block's median time. 135 GetBlockHeader(ctx context.Context, blockHash *chainhash.Hash) (*BlockHeader, error) 136 // GetBlock returns the *wire.MsgBlock. 137 GetBlock(ctx context.Context, blockHash *chainhash.Hash) (*wire.MsgBlock, error) 138 // GetTransaction returns the details of a wallet tx, if the wallet contains a 139 // tx with the provided hash. Returns asset.CoinNotFoundError if the tx is not 140 // found in the wallet. 141 GetTransaction(ctx context.Context, txHash *chainhash.Hash) (*WalletTransaction, error) 142 // GetBestBlock returns the hash and height of the wallet's best block. 143 GetBestBlock(ctx context.Context) (*chainhash.Hash, int64, error) 144 // GetBlockHash returns the hash of the mainchain block at the specified height. 145 GetBlockHash(ctx context.Context, blockHeight int64) (*chainhash.Hash, error) 146 // ListSinceBlock returns all wallet transactions confirmed since the specified 147 // height. 148 ListSinceBlock(ctx context.Context, start int32) ([]ListTransactionsResult, error) 149 // MatchAnyScript looks for any of the provided scripts in the block specified. 150 MatchAnyScript(ctx context.Context, blockHash *chainhash.Hash, scripts [][]byte) (bool, error) 151 // AccountUnlocked returns true if the account is unlocked. 152 AccountUnlocked(ctx context.Context, acctName string) (bool, error) 153 // LockAccount locks the account. 154 LockAccount(ctx context.Context, acctName string) error 155 // UnlockAccount unlocks the account. 156 UnlockAccount(ctx context.Context, passphrase []byte, acctName string) error 157 // SyncStatus returns the wallet's sync status. 158 SyncStatus(ctx context.Context) (*asset.SyncStatus, error) 159 // PeerCount returns the number of network peers to which the wallet or its 160 // backing node are connected. 161 PeerCount(ctx context.Context) (uint32, error) 162 // AddressPrivKey fetches the privkey for the specified address. 163 AddressPrivKey(ctx context.Context, address stdaddr.Address) (*secp256k1.PrivateKey, error) 164 // PurchaseTickets purchases n tickets. vspHost and vspPubKey only 165 // needed for internal wallets. Peer-to-peer mixing can be enabled if required. 166 PurchaseTickets(ctx context.Context, n int, vspHost, vspPubKey string, isMixing bool) ([]*asset.Ticket, error) 167 // Tickets returns current active ticket hashes up until they are voted 168 // or revoked. Includes unconfirmed tickets. 169 Tickets(ctx context.Context) ([]*asset.Ticket, error) 170 // VotingPreferences returns current voting preferences. 171 VotingPreferences(ctx context.Context) ([]*walletjson.VoteChoice, []*asset.TBTreasurySpend, []*walletjson.TreasuryPolicyResult, error) 172 // SetVotingPreferences sets preferences used when a ticket is chosen to 173 // be voted on. 174 SetVotingPreferences(ctx context.Context, choices, tspendPolicy, treasuryPolicy map[string]string) error 175 SetTxFee(ctx context.Context, feePerKB dcrutil.Amount) error 176 StakeInfo(ctx context.Context) (*wallet.StakeInfoData, error) 177 Reconfigure(ctx context.Context, cfg *asset.WalletConfig, net dex.Network, currentAddress string) (restart bool, err error) 178 WalletOwnsAddress(ctx context.Context, addr stdaddr.Address) (bool, error) 179 AddressUsed(ctx context.Context, addrStr string) (bool, error) 180 } 181 182 // WalletTransaction is a pared down version of walletjson.GetTransactionResult. 183 type WalletTransaction struct { 184 Confirmations int64 185 BlockHash string 186 Details []walletjson.GetTransactionDetailsResult 187 MsgTx *wire.MsgTx 188 } 189 190 // tipNotifier can be implemented if the Wallet is able to provide a stream of 191 // blocks as they are finished being processed. 192 // DRAFT NOTE: This is alternative to NotifyOnTipChange. I prefer this method, 193 // and would vote to export this interface and get rid of NotifyOnTipChange. 194 // @itswisdomagain might be using the current API though. 195 // TODO: Makes sense. 196 type tipNotifier interface { 197 tipFeed() <-chan *block 198 } 199 200 // FeeRateEstimator is satisfied by a Wallet that can provide fee rate 201 // estimates. 202 type FeeRateEstimator interface { 203 // EstimateSmartFeeRate returns a smart feerate estimate. 204 EstimateSmartFeeRate(ctx context.Context, confTarget int64, mode chainjson.EstimateSmartFeeMode) (float64, error) 205 } 206 207 // Mempooler is satisfied by a Wallet that can provide mempool info. 208 type Mempooler interface { 209 // GetRawMempool returns hashes for all txs in a node's mempool. 210 GetRawMempool(ctx context.Context) ([]*chainhash.Hash, error) 211 } 212 213 type ticketPager interface { 214 TicketPage(ctx context.Context, scanStart int32, n, skipN int) ([]*asset.Ticket, error) 215 } 216 217 // TxOutput defines properties of a transaction output, including the 218 // details of the block containing the tx, if mined. 219 type TxOutput struct { 220 *wire.TxOut 221 Tree int8 222 Addresses []string 223 Confirmations uint32 224 }