├── .gitignore ├── README.md ├── datastore.go ├── exchange_rates.go └── wallet.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | __pycache__ 10 | 11 | # Architecture specific extensions/prefixes 12 | *.[568vq] 13 | [568vq].out 14 | 15 | *.cgo1.go 16 | *.cgo2.c 17 | _cgo_defun.c 18 | _cgo_gotypes.go 19 | _cgo_export.* 20 | 21 | _testmain.go 22 | 23 | *.exe 24 | *.test 25 | *.prof 26 | .idea/ 27 | *.iml 28 | .gx/ 29 | dist 30 | 31 | # Development environment files 32 | .ackrc 33 | .tags* 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # wallet-interface 2 | Interfaces for the openbazaar-go wallet 3 | 4 | Any coin that wishes to integrate with openbazaar-go must implement this interface. 5 | -------------------------------------------------------------------------------- /datastore.go: -------------------------------------------------------------------------------- 1 | package wallet 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "math/big" 7 | "time" 8 | 9 | "github.com/btcsuite/btcd/btcec" 10 | "github.com/btcsuite/btcd/chaincfg/chainhash" 11 | "github.com/btcsuite/btcd/wire" 12 | ) 13 | 14 | type Coin interface { 15 | String() string 16 | CurrencyCode() string 17 | } 18 | 19 | type CoinType uint32 20 | 21 | const ( 22 | Bitcoin CoinType = 0 23 | Litecoin = 1 24 | Zcash = 133 25 | BitcoinCash = 145 26 | Ethereum = 60 27 | 28 | TestnetBitcoin = 1000000 29 | TestnetLitecoin = 1000001 30 | TestnetZcash = 1000133 31 | TestnetBitcoinCash = 1000145 32 | TestnetEthereum = 1000060 33 | ) 34 | 35 | func (c *CoinType) String() string { 36 | switch *c { 37 | case Bitcoin: 38 | return "Bitcoin" 39 | case BitcoinCash: 40 | return "Bitcoin Cash" 41 | case Zcash: 42 | return "Zcash" 43 | case Litecoin: 44 | return "Litecoin" 45 | case Ethereum: 46 | return "Ethereum" 47 | case TestnetBitcoin: 48 | return "Testnet Bitcoin" 49 | case TestnetBitcoinCash: 50 | return "Testnet Bitcoin Cash" 51 | case TestnetZcash: 52 | return "Testnet Zcash" 53 | case TestnetLitecoin: 54 | return "Testnet Litecoin" 55 | case TestnetEthereum: 56 | return "Testnet Ethereum" 57 | default: 58 | return "" 59 | } 60 | } 61 | 62 | func (c *CoinType) CurrencyCode() string { 63 | switch *c { 64 | case Bitcoin: 65 | return "BTC" 66 | case BitcoinCash: 67 | return "BCH" 68 | case Zcash: 69 | return "ZEC" 70 | case Litecoin: 71 | return "LTC" 72 | case Ethereum: 73 | return "ETH" 74 | case TestnetBitcoin: 75 | return "TBTC" 76 | case TestnetBitcoinCash: 77 | return "TBCH" 78 | case TestnetZcash: 79 | return "TZEC" 80 | case TestnetLitecoin: 81 | return "TLTC" 82 | case TestnetEthereum: 83 | return "TETH" 84 | default: 85 | return "" 86 | } 87 | } 88 | 89 | type Datastore interface { 90 | Utxos() Utxos 91 | Stxos() Stxos 92 | Txns() Txns 93 | Keys() Keys 94 | WatchedScripts() WatchedScripts 95 | } 96 | 97 | type Utxos interface { 98 | // Put a utxo to the database 99 | Put(utxo Utxo) error 100 | 101 | // Fetch all utxos from the db 102 | GetAll() ([]Utxo, error) 103 | 104 | // Make a utxo unspendable 105 | SetWatchOnly(utxo Utxo) error 106 | 107 | // Delete a utxo from the db 108 | Delete(utxo Utxo) error 109 | } 110 | 111 | type Stxos interface { 112 | // Put a stxo to the database 113 | Put(stxo Stxo) error 114 | 115 | // Fetch all stxos from the db 116 | GetAll() ([]Stxo, error) 117 | 118 | // Delete a stxo from the db 119 | Delete(stxo Stxo) error 120 | } 121 | 122 | type Txns interface { 123 | // Put a new transaction to the database 124 | Put(raw []byte, txid, value string, height int, timestamp time.Time, watchOnly bool) error 125 | 126 | // Fetch a tx and it's metadata given a hash 127 | Get(txid chainhash.Hash) (Txn, error) 128 | 129 | // Fetch all transactions from the db 130 | GetAll(includeWatchOnly bool) ([]Txn, error) 131 | 132 | // Update the height of a transaction 133 | UpdateHeight(txid chainhash.Hash, height int, timestamp time.Time) error 134 | 135 | // Delete a transactions from the db 136 | Delete(txid *chainhash.Hash) error 137 | } 138 | 139 | // Keys provides a database interface for the wallet to save key material, track 140 | // used keys, and manage the look ahead window. 141 | type Keys interface { 142 | // Put a bip32 key to the database 143 | Put(hash160 []byte, keyPath KeyPath) error 144 | 145 | // Import a loose private key not part of the keychain 146 | ImportKey(scriptAddress []byte, key *btcec.PrivateKey) error 147 | 148 | // Mark the script as used 149 | MarkKeyAsUsed(scriptAddress []byte) error 150 | 151 | // Fetch the last index for the given key purpose 152 | // The bool should state whether the key has been used or not 153 | GetLastKeyIndex(purpose KeyPurpose) (int, bool, error) 154 | 155 | // Returns the first unused path for the given purpose 156 | GetPathForKey(scriptAddress []byte) (KeyPath, error) 157 | 158 | // Returns an imported private key given a script address 159 | GetKey(scriptAddress []byte) (*btcec.PrivateKey, error) 160 | 161 | // Returns all imported keys 162 | GetImported() ([]*btcec.PrivateKey, error) 163 | 164 | // Get a list of unused key indexes for the given purpose 165 | GetUnused(purpose KeyPurpose) ([]int, error) 166 | 167 | // Fetch all key paths 168 | GetAll() ([]KeyPath, error) 169 | 170 | // Get the number of unused keys following the last used key 171 | // for each key purpose. 172 | GetLookaheadWindows() map[KeyPurpose]int 173 | } 174 | 175 | type WatchedScripts interface { 176 | 177 | // Add scripts to watch 178 | PutAll(scriptPubkeys [][]byte) error 179 | 180 | // Add a script to watch 181 | Put(scriptPubKey []byte) error 182 | 183 | // Return all watched scripts 184 | GetAll() ([][]byte, error) 185 | 186 | // Delete a watched script 187 | Delete(scriptPubKey []byte) error 188 | } 189 | 190 | type Utxo struct { 191 | // Previous txid and output index 192 | Op wire.OutPoint 193 | 194 | // Block height where this tx was confirmed, 0 for unconfirmed 195 | AtHeight int32 196 | 197 | // The higher the better 198 | Value string 199 | 200 | // Output script 201 | ScriptPubkey []byte 202 | 203 | // If true this utxo will not be selected for spending. The primary 204 | // purpose is track multisig UTXOs which must have separate handling 205 | // to spend. 206 | WatchOnly bool 207 | } 208 | 209 | func (utxo *Utxo) IsEqual(alt *Utxo) bool { 210 | if alt == nil { 211 | return utxo == nil 212 | } 213 | 214 | if !utxo.Op.Hash.IsEqual(&alt.Op.Hash) { 215 | return false 216 | } 217 | 218 | if utxo.Op.Index != alt.Op.Index { 219 | return false 220 | } 221 | 222 | if utxo.AtHeight != alt.AtHeight { 223 | return false 224 | } 225 | 226 | if utxo.Value != alt.Value { 227 | return false 228 | } 229 | 230 | if !bytes.Equal(utxo.ScriptPubkey, alt.ScriptPubkey) { 231 | return false 232 | } 233 | 234 | return true 235 | } 236 | 237 | type Stxo struct { 238 | // When it used to be a UTXO 239 | Utxo Utxo 240 | 241 | // The height at which it met its demise 242 | SpendHeight int32 243 | 244 | // The tx that consumed it 245 | SpendTxid chainhash.Hash 246 | } 247 | 248 | func (stxo *Stxo) IsEqual(alt *Stxo) bool { 249 | if alt == nil { 250 | return stxo == nil 251 | } 252 | 253 | if !stxo.Utxo.IsEqual(&alt.Utxo) { 254 | return false 255 | } 256 | 257 | if stxo.SpendHeight != alt.SpendHeight { 258 | return false 259 | } 260 | 261 | if !stxo.SpendTxid.IsEqual(&alt.SpendTxid) { 262 | return false 263 | } 264 | 265 | return true 266 | } 267 | 268 | type Txn struct { 269 | // Transaction ID 270 | Txid string 271 | 272 | // The value relevant to the wallet 273 | Value string 274 | 275 | // The height at which it was mined 276 | Height int32 277 | 278 | // The time the transaction was first seen 279 | Timestamp time.Time 280 | 281 | // This transaction only involves a watch only address 282 | WatchOnly bool 283 | 284 | // The number of confirmations on a transaction. This does not need to be saved in 285 | // the database but should be calculated when the Transactions() method is called. 286 | Confirmations int64 287 | 288 | // The state of the transaction (confirmed, unconfirmed, dead, etc). Implementations 289 | // have some flexibility in describing their transactions. Like confirmations, this 290 | // is best calculated when the Transactions() method is called. 291 | Status StatusCode 292 | 293 | // If the Status is Error the ErrorMessage should describe the problem 294 | ErrorMessage string 295 | 296 | // Raw transaction bytes 297 | Bytes []byte 298 | 299 | FromAddress string 300 | ToAddress string 301 | 302 | Outputs []TransactionOutput 303 | } 304 | 305 | type StatusCode string 306 | 307 | const ( 308 | StatusUnconfirmed StatusCode = "UNCONFIRMED" 309 | StatusPending = "PENDING" 310 | StatusConfirmed = "CONFIRMED" 311 | StatusStuck = "STUCK" 312 | StatusDead = "DEAD" 313 | StatusError = "ERROR" 314 | ) 315 | 316 | type KeyPath struct { 317 | Purpose KeyPurpose 318 | Index int 319 | } 320 | 321 | type CurrencyDefinition struct { 322 | Code string 323 | Divisibility int64 324 | } 325 | type CurrencyValue struct { 326 | Currency CurrencyDefinition 327 | Value big.Int 328 | ValueSerialization json.Number 329 | } 330 | -------------------------------------------------------------------------------- /exchange_rates.go: -------------------------------------------------------------------------------- 1 | package wallet 2 | 3 | type ExchangeRates interface { 4 | 5 | /* Fetch the exchange rate for the given currency 6 | It is OK if this returns from a cache. */ 7 | GetExchangeRate(currencyCode string) (float64, error) 8 | 9 | // Update the prices with the current exchange rate before returning 10 | GetLatestRate(currencyCode string) (float64, error) 11 | 12 | // Returns all available rates 13 | GetAllRates(cacheOK bool) (map[string]float64, error) 14 | 15 | /* Return the number of currency units per coin. For example, in bitcoin 16 | this is 100m satoshi per BTC. This is used when converting from fiat 17 | to the smaller currency unit. */ 18 | UnitsPerCoin() int64 19 | } 20 | -------------------------------------------------------------------------------- /wallet.go: -------------------------------------------------------------------------------- 1 | package wallet 2 | 3 | import ( 4 | "errors" 5 | "math/big" 6 | "time" 7 | 8 | "github.com/btcsuite/btcd/chaincfg/chainhash" 9 | btc "github.com/btcsuite/btcutil" 10 | hd "github.com/btcsuite/btcutil/hdkeychain" 11 | ) 12 | 13 | // Wallet interface is used by openbazaar-go for both normal wallet operation (sending 14 | // and receiving) as well as for handling multisig escrow payment as part of its order flow. 15 | // The following is a very high level of the order flow and how it relates to the methods 16 | // described by this interface. 17 | 18 | // 1) The buyer clicks a button to place an order with a vendor. In addition to populating 19 | // the order with all the relevant information, the buyer's node calls the `GenerateMultisigScript` 20 | // interface method to generate an address and redeem script that is unique for the order. 21 | // The order is then sent over to the vendor for evaluation. 22 | // 23 | // 2) The vendor receives the order, takes his public key as well as the key provided by the 24 | // buyer and moderator and likewise calls `GenerateMultisigScript` and compares the returned 25 | // address and redeem script to those provide by the buyer in the order to make sure the 26 | // buyer provided valid information. He then sends a message to the buyer notifying that he 27 | // has accepted the order. 28 | // 29 | // 3) The buyer can then either send funds into the multisig address using an external wallet 30 | // or if he wishes to use the built-in wallet, he calls the `Spend` interface method and 31 | // provides the multisig address as the destination. 32 | // 33 | // 4) After the buyer receives the goods he clicks the complete order button in the UI to 34 | // leave a review and release the funds to the vendor. His node calls the `CreateMultisigSignature` 35 | // interface method to generate a signature for the transaction releasing the funds. The signature is 36 | // sent over to the vendor along with his review. 37 | // 38 | // 5) The vendor receives the review and the signature then calls `CreateMultisigSignature` 39 | // himself to generate his signature on the transaction. We now have the two signatures necessary 40 | // to release the funds. The vendor then calls the `Multisign` interface method and includes 41 | // both signatures. The multisign function combines all the signatures into one valid transaction 42 | // then broadcasts it to the network. 43 | // 44 | // The above example is only one possible order flow. There are other variants based on whether or 45 | // not the vendor is online or offline and whether or not the buyer is doing a direct payment or 46 | // escrowed payment. 47 | type Wallet interface { 48 | walletMustManager 49 | walletMustKeysmither 50 | walletMustBanker 51 | walletCanBumpFee 52 | } 53 | 54 | var ( 55 | // ErrInsufficientFunds is returned when the wallet is unable to send the amount specified due to the balance being too low 56 | ErrInsufficientFunds = errors.New("ERROR_INSUFFICIENT_FUNDS") 57 | ) 58 | 59 | // WalletMustManuallyAssociateTransactionToOrder MUST be checked for by openbazaar-go to ensure 60 | // that wallets which require manual association between transactions and orders are properly 61 | // associated. If the interface is supported, AssociateTransactionToOrder must be called as 62 | // early as is reasonable to ensure proper reporting of payment. 63 | type WalletMustManuallyAssociateTransactionToOrder interface { 64 | // AssociateTransactionWithOrder must be called for wallets which implement it to support 65 | // wallet implementations which are not able to generate unique Addresses on a per-Order 66 | // basis. It should be called as soon as the wallet transaction and referenceID are both 67 | // known by the openbazaar-go node (which should be reported from the buyer to the vendor). 68 | AssociateTransactionWithOrder(cb TransactionCallback) 69 | } 70 | 71 | type walletMustManager interface { 72 | // Start is called when the openbazaar-go daemon starts up. At this point in time 73 | // the wallet implementation should start syncing and/or updating balances, but 74 | // not before. 75 | Start() 76 | 77 | // Close should cleanly disconnect from the wallet and finish writing 78 | // anything it needs to to disk. 79 | Close() 80 | 81 | // CurrencyCode returns the currency code this wallet implements. For example, "BTC". 82 | // When running on testnet a `T` should be prepended. For example "TBTC". 83 | CurrencyCode() string 84 | 85 | // ExchangeRates returns an ExchangeRates implementation which will provide 86 | // fiat exchange rate data for this coin. 87 | ExchangeRates() ExchangeRates 88 | 89 | // AddWatchedAddresses adds an address to the wallet to get notifications back when coins 90 | // are received or spent from it. These watch only addresses should be persisted between 91 | // sessions and upon each startup the wallet should be made to listen for transactions 92 | // involving them. 93 | AddWatchedAddresses(addrs ...btc.Address) error 94 | 95 | // AddTransactionListener is how openbazaar-go registers to receive a callback whenever 96 | // a transaction is received that is relevant to this wallet or any of its watch only 97 | // addresses. An address is considered relevant if any inputs or outputs match an address 98 | // owned by this wallet, or being watched by the wallet via AddWatchedAddress method. 99 | AddTransactionListener(func(TransactionCallback)) 100 | 101 | // IsDust returns whether the amount passed in is considered dust by network. This 102 | // method is called when building payout transactions from the multisig to the various 103 | // participants. If the amount that is supposed to be sent to a given party is below 104 | // the dust threshold, openbazaar-go will not pay that party to avoid building a transaction 105 | // that never confirms. 106 | IsDust(amount big.Int) bool 107 | 108 | // CurrentAddress returns an address suitable for receiving payments. `purpose` specifies 109 | // whether the address should be internal or external. External addresses are typically 110 | // requested when receiving funds from outside the wallet .Internal addresses are typically 111 | // change addresses. For utxo based coins we expect this function will return the same 112 | // address so long as that address is unused. Whenever the address receives a payment, 113 | // CurrentAddress should start returning a new, unused address. 114 | CurrentAddress(purpose KeyPurpose) btc.Address 115 | 116 | // NewAddress returns a new, never-before-returned address. It is critical that it returns 117 | // a never-before-returned address because this function is called when fetching an address 118 | // for a direct payment order. In this case we expect the address to be unique for each order 119 | // if it's not unique, it will cause problems as we can't determine which order the payment 120 | // was for. 121 | NewAddress(purpose KeyPurpose) btc.Address 122 | 123 | // DecodeAddress parses the address string and return an address interface. 124 | DecodeAddress(addr string) (btc.Address, error) 125 | 126 | // ScriptToAddress takes a raw output script (the full script, not just a hash160) and 127 | // returns the corresponding address. This should be considered deprecated as we 128 | // intend to remove it once most people have upgraded, but for now it needs to remain. 129 | ScriptToAddress(script []byte) (btc.Address, error) 130 | 131 | // Balance returns the confirmed and unconfirmed aggregate balance for the wallet. 132 | // For utxo based wallets, if a spend of confirmed coins is made, the resulting "change" 133 | // should be also counted as confirmed even if the spending transaction is unconfirmed. 134 | // The reason for this that if the spend never confirms, no coins will be lost to the wallet. 135 | // 136 | // The returned balances should be in the coin's base unit (for example: satoshis) 137 | Balance() (confirmed, unconfirmed CurrencyValue) 138 | 139 | // Transactions returns a list of transactions for this wallet. 140 | Transactions() ([]Txn, error) 141 | 142 | // GetTransaction return info on a specific transaction given the txid. 143 | GetTransaction(txid chainhash.Hash) (Txn, error) 144 | 145 | // ChainTip returns the best block hash and height of the blockchain. 146 | ChainTip() (uint32, chainhash.Hash) 147 | 148 | // ReSyncBlockchain is called in response to a user action to rescan transactions. API based 149 | // wallets should do another scan of their addresses to find anything missing. Full node, or SPV 150 | // wallets should rescan/re-download blocks starting at the fromTime. 151 | ReSyncBlockchain(fromTime time.Time) 152 | 153 | // GetConfirmations returns the number of confirmations and the height for a transaction. 154 | GetConfirmations(txid chainhash.Hash) (confirms, atHeight uint32, err error) 155 | } 156 | 157 | type walletMustKeysmither interface { 158 | // ChildKey generate a child key using the given chaincode. Each openbazaar-go node 159 | // keeps a master key (an hd secp256k1 key) that it uses in multisig transactions. 160 | // Rather than use the key directly (which would result in an on chain privacy leak), 161 | // we create a random chaincode for each order (which is not made public) and a child 162 | // key is derived from the master key using the chaincode. The child key for each party 163 | // to the order (buyer, vendor, moderator) is what is used to create the multisig. This 164 | // function leaves it up the wallet implementation to decide how to derive the child key 165 | // so long as it's deterministic and uses the chaincode and the returned key is pseudorandom. 166 | ChildKey(keyBytes []byte, chaincode []byte, isPrivateKey bool) (*hd.ExtendedKey, error) 167 | 168 | // HasKey returns whether or not the wallet has the key for the given address. This method 169 | // is called by openbazaar-go when validating payouts from multisigs. It makes sure the 170 | // transaction that the other party(s) signed does indeed pay to an address that we 171 | // control. 172 | HasKey(addr btc.Address) bool 173 | 174 | // GenerateMultisigScript should deterministically create a redeem script and address from the information provided. 175 | // This method should be strictly limited to taking the input data, combining it to produce the redeem script and 176 | // address and that's it. There is no need to interact with the network or make any transactions when this is called. 177 | // 178 | // Openbazaar-go will call this method in the following situations: 179 | // 1) When the buyer places an order he passes in the relevant keys for each party to get back the address where 180 | // the funds should be sent and the redeem script. The redeem script is saved in order (and openbazaar-go database). 181 | // 182 | // 2) The vendor calls this method when he receives and order so as to validate that the address they buyer is sending 183 | // funds to is indeed correctly constructed. If this method fails to return the same values for the vendor as it 184 | // did the buyer, the vendor will reject the order. 185 | // 186 | // 3) The moderator calls this function upon receiving a dispute so that he can validate the payment address for the 187 | // order and make sure neither party is trying to maliciously lie about the details of the dispute to get the moderator 188 | // to release the funds. 189 | // 190 | // Note that according to the order flow, this method is called by the buyer *before* the order is sent to the vendor, 191 | // and before the vendor validates the order. Only after the buyer hears back from the vendor does the buyer send 192 | // funds (either from an external wallet or via the `Spend` method) to the address specified in this method's return. 193 | // 194 | // `threshold` is the number of keys required to release the funds from the address. If `threshold` is two and len(keys) 195 | // is three, this is a two of three multisig. If `timeoutKey` is not nil, then the script should allow the funds to 196 | // be released with a signature from the `timeoutKey` after the `timeout` duration has passed. 197 | // For example: 198 | // OP_IF 2 3 OP_ELSE OP_CHECKSEQUENCEVERIFY OP_CHECKSIG OP_ENDIF 199 | // 200 | // If `timeoutKey` is nil then the a normal multisig without a timeout should be created. 201 | GenerateMultisigScript(keys []hd.ExtendedKey, threshold int, timeout time.Duration, timeoutKey *hd.ExtendedKey) (addr btc.Address, redeemScript []byte, err error) 202 | 203 | // CreateMultisigSignature should build a transaction using the given inputs and outputs and sign it with the 204 | // provided key. A list of signatures (one for each input) should be returned. 205 | // 206 | // This method is called by openbazaar-go by each party whenever they decide to release the funds from escrow. 207 | // This method should not actually move any funds or make any transactions, only create necessary signatures to 208 | // do so. The caller will then take the signature and share it with the other parties. Once all parties have shared 209 | // their signatures, the person who wants to release the funds collects them and uses them as an input to the 210 | // `Multisign` method. 211 | CreateMultisigSignature(ins []TransactionInput, outs []TransactionOutput, key *hd.ExtendedKey, redeemScript []byte, feePerByte big.Int) ([]Signature, error) 212 | 213 | // Multisign collects all of the signatures generated by the `CreateMultisigSignature` function and builds a final 214 | // transaction that can then be broadcast to the blockchain. The []byte return is the raw transaction. It should be 215 | // broadcasted if `broadcast` is true. If the signatures combine and produce an invalid transaction then an error 216 | // should be returned. 217 | // 218 | // This method is called by openbazaar-go by whichever party to the escrow is trying to release the funds only after 219 | // all needed parties have signed using `CreateMultisigSignature` and have shared their signatures with each other. 220 | Multisign(ins []TransactionInput, outs []TransactionOutput, sigs1 []Signature, sigs2 []Signature, redeemScript []byte, feePerByte big.Int, broadcast bool) ([]byte, error) 221 | } 222 | 223 | type walletMustBanker interface { 224 | // GetFeePerByte returns the current fee per byte for the given fee level. There 225 | // are three fee levels ― priority, normal, and economic. 226 | // 227 | //The returned value should be in the coin's base unit (for example: satoshis). 228 | GetFeePerByte(feeLevel FeeLevel) big.Int 229 | 230 | // Spend transfers the given amount of coins (in the coin's base unit. For example: in 231 | // satoshis) to the given address using the provided fee level. Openbazaar-go calls 232 | // this method in two places. 1) When the user requests a normal transfer from their 233 | // wallet to another address. 2) When clicking 'pay from internal wallet' to fund 234 | // an order the user just placed. 235 | // It also includes a referenceID which basically refers to the order the spend will affect 236 | // 237 | // If spendAll is true the amount field will be ignored and all the funds in the wallet will 238 | // be swept to the provided payment address. For most coins this entails subtracting the 239 | // transaction fee from the total amount being sent rather than adding it on as is normally 240 | // the case when spendAll is false. 241 | Spend(amount big.Int, addr btc.Address, feeLevel FeeLevel, referenceID string, spendAll bool) (*chainhash.Hash, error) 242 | 243 | // EstimateFee should return the estimate fee that will be required to make a transaction 244 | // spending from the given inputs to the given outputs. FeePerByte is denominated in 245 | // the coin's base unit (for example: satoshis). 246 | EstimateFee(ins []TransactionInput, outs []TransactionOutput, feePerByte big.Int) big.Int 247 | 248 | // EstimateSpendFee should return the anticipated fee to transfer a given amount of coins 249 | // out of the wallet at the provided fee level. Typically this involves building a 250 | // transaction with enough inputs to cover the request amount and calculating the size 251 | // of the transaction. It is OK, if a transaction comes in after this function is called 252 | // that changes the estimated fee as it's only intended to be an estimate. 253 | // 254 | // All amounts should be in the coin's base unit (for example: satoshis). 255 | EstimateSpendFee(amount big.Int, feeLevel FeeLevel) (big.Int, error) 256 | 257 | // SweepAddress should sweep all the funds from the provided inputs into the provided `address` using the given 258 | // `key`. If `address` is nil, the funds should be swept into an internal address own by this wallet. 259 | // If the `redeemScript` is not nil, this should be treated as a multisig (p2sh) address and signed accordingly. 260 | // 261 | // This method is called by openbazaar-go in the following scenarios: 262 | // 1) The buyer placed a direct order to a vendor who was offline. The buyer sent funds into a 1 of 2 multisig. 263 | // Upon returning online the vendor accepts the order and calls SweepAddress to move the funds into his wallet. 264 | // 265 | // 2) Same as above but the buyer wishes to cancel the order before the vendor comes online. He calls SweepAddress 266 | // to return the funds from the 1 of 2 multisig back into has wallet. 267 | // 268 | // 3) Same as above but rather than accepting the order, the vendor rejects it. When the buyer receives the reject 269 | // message he calls SweepAddress to move the funds back into his wallet. 270 | // 271 | // 4) The timeout has expired on a 2 of 3 multisig. The vendor calls SweepAddress to claim the funds. 272 | SweepAddress(ins []TransactionInput, address *btc.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel FeeLevel) (*chainhash.Hash, error) 273 | } 274 | 275 | type walletCanBumpFee interface { 276 | // BumpFee should attempt to bump the fee on a given unconfirmed transaction (if possible) to 277 | // try to get it confirmed and return the txid of the new transaction (if one exists). 278 | // Since this method is only called in response to user action, it is acceptable to 279 | // return an error if this functionality is not available in this wallet or on the network. 280 | BumpFee(txid chainhash.Hash) (*chainhash.Hash, error) 281 | } 282 | 283 | type FeeLevel int 284 | 285 | const ( 286 | PRIOIRTY FeeLevel = 0 287 | NORMAL = 1 288 | ECONOMIC = 2 289 | FEE_BUMP = 3 290 | SUPER_ECONOMIC = 4 291 | ) 292 | 293 | // The end leaves on the HD wallet have only two possible values. External keys are those given 294 | // to other people for the purpose of receiving transactions. These may include keys used for 295 | // refund addresses. Internal keys are used only by the wallet, primarily for change addresses 296 | // but could also be used for shuffling around UTXOs. 297 | type KeyPurpose int 298 | 299 | const ( 300 | EXTERNAL KeyPurpose = 0 301 | INTERNAL = 1 302 | ) 303 | 304 | // This callback is passed to any registered transaction listeners when a transaction is detected 305 | // for the wallet. 306 | type TransactionCallback struct { 307 | Txid string 308 | Outputs []TransactionOutput 309 | Inputs []TransactionInput 310 | Height int32 311 | Timestamp time.Time 312 | Value big.Int 313 | WatchOnly bool 314 | BlockTime time.Time 315 | } 316 | 317 | type TransactionOutput struct { 318 | Address btc.Address 319 | Value big.Int 320 | Index uint32 321 | OrderID string 322 | } 323 | 324 | type TransactionInput struct { 325 | OutpointHash []byte 326 | OutpointIndex uint32 327 | LinkedAddress btc.Address 328 | Value big.Int 329 | OrderID string 330 | } 331 | 332 | // OpenBazaar uses p2sh addresses for escrow. This object can be used to store a record of a 333 | // transaction going into or out of such an address. Incoming transactions should have a positive 334 | // value and be market as spent when the UXTO is spent. Outgoing transactions should have a 335 | // negative value. The spent field isn't relevant for outgoing transactions. 336 | type TransactionRecord struct { 337 | Txid string 338 | Index uint32 339 | Value big.Int 340 | Address string 341 | Spent bool 342 | Timestamp time.Time 343 | } 344 | 345 | // This object contains a single signature for a multisig transaction. InputIndex specifies 346 | // the index for which this signature applies. 347 | type Signature struct { 348 | InputIndex uint32 349 | Signature []byte 350 | } 351 | 352 | // Errors 353 | var ( 354 | ErrorDustAmount error = errors.New("amount is below network dust treshold") 355 | ) 356 | --------------------------------------------------------------------------------