From 4737306ed4ac97c7b0eb389356494d0232bac963 Mon Sep 17 00:00:00 2001 From: Brian Hoffman Date: Thu, 4 Jun 2020 14:02:21 -0400 Subject: [PATCH 1/2] Change openbazaar-go to support custom fee --- core/refunds.go | 8 ++++++-- core/spend.go | 10 +++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/core/refunds.go b/core/refunds.go index 139f1b5046..50a1babaa2 100644 --- a/core/refunds.go +++ b/core/refunds.go @@ -3,11 +3,12 @@ package core import ( "encoding/hex" "errors" - "github.com/OpenBazaar/openbazaar-go/repo" "math/big" "strings" "time" + "github.com/OpenBazaar/openbazaar-go/repo" + "github.com/OpenBazaar/openbazaar-go/pb" "github.com/OpenBazaar/wallet-interface" "github.com/golang/protobuf/proto" @@ -97,7 +98,10 @@ func (n *OpenBazaarNode) RefundOrder(contract *pb.RicardianContract, records []* if err != nil { return err } - txid, err := wal.Spend(*outValue, refundAddr, wallet.NORMAL, orderID, false) + fee := wallet.Fee{ + FeeLevel: wallet.NORMAL, + } + txid, err := wal.Spend(*outValue, refundAddr, fee, orderID, false) if err != nil { return err } diff --git a/core/spend.go b/core/spend.go index 38135aedbf..f81fff0a79 100644 --- a/core/spend.go +++ b/core/spend.go @@ -29,6 +29,7 @@ type SpendRequest struct { OrderID string `json:"orderId"` RequireAssociatedOrder bool `json:"requireOrder"` SpendAll bool `json:"spendAll"` + CustomFee string `json:"customFee"` } type SpendResponse struct { @@ -99,11 +100,18 @@ func (n *OpenBazaarNode) Spend(args *SpendRequest) (*SpendResponse, error) { feeLevel = wallet.ECONOMIC case "SUPER_ECONOMIC": feeLevel = wallet.SUPER_ECONOMIC + case "CUSTOM": + feeLevel = wallet.CUSTOM default: feeLevel = wallet.ECONOMIC } - txid, err := wal.Spend(*amt, addr, feeLevel, args.OrderID, args.SpendAll) + fee := wallet.Fee{ + FeeLevel: feeLevel, + CustomFee: args.CustomFee, + } + + txid, err := wal.Spend(*amt, addr, fee, args.OrderID, args.SpendAll) if err != nil { switch { case err == wallet.ErrInsufficientFunds: From 2e1e21afe001d22da3447f87d62166aab5f14b6e Mon Sep 17 00:00:00 2001 From: Brian Hoffman Date: Thu, 4 Jun 2020 14:02:35 -0400 Subject: [PATCH 2/2] Custom Fees for vendored multiwallet items --- .../go-ethwallet/wallet/erc20_wallet.go | 2 +- .../OpenBazaar/go-ethwallet/wallet/wallet.go | 78 +++++++++++++++---- .../OpenBazaar/multiwallet/bitcoin/sign.go | 42 +++++++--- .../OpenBazaar/multiwallet/bitcoin/wallet.go | 6 +- .../multiwallet/bitcoincash/sign.go | 42 +++++++--- .../multiwallet/bitcoincash/wallet.go | 7 +- .../OpenBazaar/multiwallet/litecoin/sign.go | 44 ++++++++--- .../OpenBazaar/multiwallet/litecoin/wallet.go | 6 +- .../OpenBazaar/multiwallet/zcash/sign.go | 42 +++++++--- .../OpenBazaar/multiwallet/zcash/wallet.go | 6 +- .../OpenBazaar/spvwallet/sortsignsend.go | 47 ++++++++--- .../OpenBazaar/wallet-interface/wallet.go | 8 +- 12 files changed, 248 insertions(+), 82 deletions(-) diff --git a/vendor/github.com/OpenBazaar/go-ethwallet/wallet/erc20_wallet.go b/vendor/github.com/OpenBazaar/go-ethwallet/wallet/erc20_wallet.go index d842fa7bb2..3dde3826f1 100644 --- a/vendor/github.com/OpenBazaar/go-ethwallet/wallet/erc20_wallet.go +++ b/vendor/github.com/OpenBazaar/go-ethwallet/wallet/erc20_wallet.go @@ -348,7 +348,7 @@ func (wallet *ERC20Wallet) GetFeePerByte(feeLevel wi.FeeLevel) uint64 { } // Spend - Send ether to an external wallet -func (wallet *ERC20Wallet) Spend(amount big.Int, addr btcutil.Address, feeLevel wi.FeeLevel, referenceID string) (*chainhash.Hash, error) { +func (wallet *ERC20Wallet) Spend(amount big.Int, addr btcutil.Address, fee wi.Fee, referenceID string) (*chainhash.Hash, error) { var hash common.Hash var h *chainhash.Hash var err error diff --git a/vendor/github.com/OpenBazaar/go-ethwallet/wallet/wallet.go b/vendor/github.com/OpenBazaar/go-ethwallet/wallet/wallet.go index ec0bba1887..d721e957b3 100644 --- a/vendor/github.com/OpenBazaar/go-ethwallet/wallet/wallet.go +++ b/vendor/github.com/OpenBazaar/go-ethwallet/wallet/wallet.go @@ -675,7 +675,7 @@ func (wallet *EthereumWallet) GetFeePerByte(feeLevel wi.FeeLevel) big.Int { switch feeLevel { case wi.NORMAL: ret, _ = big.NewFloat(est.Average * 100000000).Int(nil) - case wi.ECONOMIC: + case wi.ECONOMIC, wi.SUPER_ECONOMIC: ret, _ = big.NewFloat(est.SafeLow * 100000000).Int(nil) case wi.PRIORITY, wi.FEE_BUMP: ret, _ = big.NewFloat(est.Fast * 100000000).Int(nil) @@ -684,7 +684,7 @@ func (wallet *EthereumWallet) GetFeePerByte(feeLevel wi.FeeLevel) big.Int { } // Spend - Send ether to an external wallet -func (wallet *EthereumWallet) Spend(amount big.Int, addr btcutil.Address, feeLevel wi.FeeLevel, referenceID string, spendAll bool) (*chainhash.Hash, error) { +func (wallet *EthereumWallet) Spend(amount big.Int, addr btcutil.Address, fee wi.Fee, referenceID string, spendAll bool) (*chainhash.Hash, error) { var ( hash common.Hash h *chainhash.Hash @@ -694,9 +694,20 @@ func (wallet *EthereumWallet) Spend(amount big.Int, addr btcutil.Address, feeLev ) actualRecipient := addr + var feePerBytes big.Int + if fee.CustomFee != "" { + f, ok := new(big.Int).SetString(fee.CustomFee, 10) + if !ok { + return nil, errors.New("bad custom fee") + } + feePerBytes = *f + } else { + feePerBytes = wallet.GetFeePerByte(fee.FeeLevel) + } + if referenceID == "" { // no referenceID means this is a direct transfer - hash, err = wallet.Transfer(util.EnsureCorrectPrefix(addr.String()), &amount, spendAll, wallet.GetFeePerByte(feeLevel)) + hash, err = wallet.Transfer(util.EnsureCorrectPrefix(addr.String()), &amount, spendAll, feePerBytes) } else { watchOnly = true // this is a spend which means it has to be linked to an order @@ -731,16 +742,26 @@ func (wallet *EthereumWallet) Spend(amount big.Int, addr btcutil.Address, feeLev } addrScrHash := common.HexToAddress(scrHash) actualRecipient = EthAddress{address: &addrScrHash} - hash, _, err = wallet.callAddTransaction(ethScript, &amount, feeLevel) + hash, _, err = wallet.callAddTransaction(ethScript, &amount, fee) if err != nil { log.Errorf("error call add txn: %v", err) return nil, wi.ErrInsufficientFunds } } else { - if !wallet.balanceCheck(feeLevel, amount) { + if !wallet.balanceCheck(fee, amount) { return nil, wi.ErrInsufficientFunds } - hash, err = wallet.Transfer(util.EnsureCorrectPrefix(addr.String()), &amount, spendAll, wallet.GetFeePerByte(feeLevel)) + var feePerByte big.Int + if fee.CustomFee != "" { + f, ok := new(big.Int).SetString(fee.CustomFee, 10) + if !ok { + return nil, errors.New("bad custom fee") + } + feePerByte = *f + } else { + feePerByte = wallet.GetFeePerByte(fee.FeeLevel) + } + hash, err = wallet.Transfer(util.EnsureCorrectPrefix(addr.String()), &amount, spendAll, feePerByte) } if err != nil { return nil, err @@ -877,14 +898,24 @@ func (wallet *EthereumWallet) EstimateFee(ins []wi.TransactionInput, outs []wi.T return *sum } -func (wallet *EthereumWallet) balanceCheck(feeLevel wi.FeeLevel, amount big.Int) bool { - fee := wallet.GetFeePerByte(feeLevel) - if fee.Int64() == 0 { +func (wallet *EthereumWallet) balanceCheck(fee wi.Fee, amount big.Int) bool { + var feePerByte big.Int + if fee.CustomFee != "" { + f, ok := new(big.Int).SetString(fee.CustomFee, 10) + if !ok { + return false + } + feePerByte = *f + } else { + feePerByte = wallet.GetFeePerByte(fee.FeeLevel) + } + + if feePerByte.Int64() == 0 { return false } // lets check if the caller has enough balance to make the // multisign call - requiredBalance := new(big.Int).Mul(&fee, big.NewInt(maxGasLimit)) + requiredBalance := new(big.Int).Mul(&feePerByte, big.NewInt(maxGasLimit)) requiredBalance = new(big.Int).Add(requiredBalance, &amount) currentBalance, err := wallet.GetBalance() if err != nil { @@ -900,7 +931,10 @@ func (wallet *EthereumWallet) balanceCheck(feeLevel wi.FeeLevel, amount big.Int) // EstimateSpendFee - Build a spend transaction for the amount and return the transaction fee func (wallet *EthereumWallet) EstimateSpendFee(amount big.Int, feeLevel wi.FeeLevel) (big.Int, error) { - if !wallet.balanceCheck(feeLevel, amount) { + fee := wi.Fee { + FeeLevel: feeLevel, + } + if !wallet.balanceCheck(fee, amount) { return *big.NewInt(0), wi.ErrInsufficientFunds } gas, err := wallet.client.EstimateGasSpend(wallet.account.Address(), &amount) @@ -940,7 +974,7 @@ func (wallet *EthereumWallet) ExchangeRates() wi.ExchangeRates { return wallet.exchangeRates } -func (wallet *EthereumWallet) callAddTransaction(script EthRedeemScript, value *big.Int, feeLevel wi.FeeLevel) (common.Hash, uint64, error) { +func (wallet *EthereumWallet) callAddTransaction(script EthRedeemScript, value *big.Int, fee wi.Fee) (common.Hash, uint64, error) { h := common.BigToHash(big.NewInt(0)) @@ -954,9 +988,21 @@ func (wallet *EthereumWallet) callAddTransaction(script EthRedeemScript, value * if err != nil { log.Fatal(err) } - gasPriceETHGAS := wallet.GetFeePerByte(feeLevel) - if gasPriceETHGAS.Int64() < gasPrice.Int64() { - gasPriceETHGAS = *gasPrice + + var gasPriceETHGAS int64 + if fee.CustomFee != "" { + cf, err := strconv.Atoi(fee.CustomFee) + if err != nil { + return h, nonce, err + } + gasPriceETHGAS = int64(cf) + } else { + gas := wallet.GetFeePerByte(fee.FeeLevel) + gasPriceETHGAS = gas.Int64() + } + + if gasPriceETHGAS < gasPrice.Int64() { + gasPriceETHGAS = gasPrice.Int64() } auth := bind.NewKeyedTransactor(wallet.account.privateKey) @@ -967,7 +1013,7 @@ func (wallet *EthereumWallet) callAddTransaction(script EthRedeemScript, value * // lets check if the caller has enough balance to make the // multisign call - if !wallet.balanceCheck(feeLevel, *big.NewInt(0)) { + if !wallet.balanceCheck(fee, *big.NewInt(0)) { // the wallet does not have the required balance return h, nonce, wi.ErrInsufficientFunds } diff --git a/vendor/github.com/OpenBazaar/multiwallet/bitcoin/sign.go b/vendor/github.com/OpenBazaar/multiwallet/bitcoin/sign.go index 07baff1463..00f518648f 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/bitcoin/sign.go +++ b/vendor/github.com/OpenBazaar/multiwallet/bitcoin/sign.go @@ -29,7 +29,7 @@ import ( "github.com/OpenBazaar/multiwallet/util" ) -func (w *BitcoinWallet) buildTx(amount int64, addr btc.Address, feeLevel wi.FeeLevel, optionalOutput *wire.TxOut) (*wire.MsgTx, error) { +func (w *BitcoinWallet) buildTx(amount int64, addr btc.Address, fee wi.Fee, optionalOutput *wire.TxOut) (*wire.MsgTx, error) { // Check for dust script, _ := txscript.PayToAddrScript(addr) if txrules.IsDustAmount(btc.Amount(amount), len(script), txrules.DefaultRelayFeePerKb) { @@ -82,8 +82,17 @@ func (w *BitcoinWallet) buildTx(amount int64, addr btc.Address, feeLevel wi.FeeL } // Get the fee per kilobyte - f := w.GetFeePerByte(feeLevel) - feePerKB := f.Int64() * 1000 + var feePerKB int64 + if fee.CustomFee != "" { + cf, err := strconv.Atoi(fee.CustomFee) + if err != nil { + return nil, err + } + feePerKB = int64(cf) * 1000 + } else { + f := w.GetFeePerByte(fee.FeeLevel) + feePerKB = f.Int64() * 1000 + } // outputs out := wire.NewTxOut(amount, script) @@ -133,7 +142,7 @@ func (w *BitcoinWallet) buildTx(amount int64, addr btc.Address, feeLevel wi.FeeL return authoredTx.Tx, nil } -func (w *BitcoinWallet) buildSpendAllTx(addr btc.Address, feeLevel wi.FeeLevel) (*wire.MsgTx, error) { +func (w *BitcoinWallet) buildSpendAllTx(addr btc.Address, fee wi.Fee) (*wire.MsgTx, error) { tx := wire.NewMsgTx(1) height, _ := w.ws.ChainTip() @@ -152,18 +161,28 @@ func (w *BitcoinWallet) buildSpendAllTx(addr btc.Address, feeLevel wi.FeeLevel) } // Get the fee - fee0 := w.GetFeePerByte(feeLevel) - feePerByte := fee0.Int64() + var feePerByte int64 + if fee.CustomFee != "" { + cf, err := strconv.Atoi(fee.CustomFee) + if err != nil { + return nil, err + } + feePerByte = int64(cf) + } else { + fee0 := w.GetFeePerByte(fee.FeeLevel) + feePerByte = fee0.Int64() + } + estimatedSize := EstimateSerializeSize(1, []*wire.TxOut{wire.NewTxOut(0, script)}, false, P2PKH) - fee := int64(estimatedSize) * feePerByte + feeCost := int64(estimatedSize) * feePerByte // Check for dust output - if txrules.IsDustAmount(btc.Amount(totalIn-fee), len(script), txrules.DefaultRelayFeePerKb) { + if txrules.IsDustAmount(btc.Amount(totalIn-feeCost), len(script), txrules.DefaultRelayFeePerKb) { return nil, wi.ErrorDustAmount } // Build the output - out := wire.NewTxOut(totalIn-fee, script) + out := wire.NewTxOut(totalIn-feeCost, script) tx.TxOut = append(tx.TxOut, out) // BIP 69 sorting @@ -649,7 +668,10 @@ func (w *BitcoinWallet) estimateSpendFee(amount int64, feeLevel wi.FeeLevel) (ui if err != nil { return 0, err } - tx, err := w.buildTx(amount, addr, feeLevel, nil) + fee := wi.Fee{ + FeeLevel: feeLevel, + } + tx, err := w.buildTx(amount, addr, fee, nil) if err != nil { return 0, err } diff --git a/vendor/github.com/OpenBazaar/multiwallet/bitcoin/wallet.go b/vendor/github.com/OpenBazaar/multiwallet/bitcoin/wallet.go index 147856b6c5..21413230b2 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/bitcoin/wallet.go +++ b/vendor/github.com/OpenBazaar/multiwallet/bitcoin/wallet.go @@ -293,18 +293,18 @@ func (w *BitcoinWallet) GetFeePerByte(feeLevel wi.FeeLevel) big.Int { return *big.NewInt(int64(w.fp.GetFeePerByte(feeLevel))) } -func (w *BitcoinWallet) Spend(amount big.Int, addr btc.Address, feeLevel wi.FeeLevel, referenceID string, spendAll bool) (*chainhash.Hash, error) { +func (w *BitcoinWallet) Spend(amount big.Int, addr btc.Address, fee wi.Fee, referenceID string, spendAll bool) (*chainhash.Hash, error) { var ( tx *wire.MsgTx err error ) if spendAll { - tx, err = w.buildSpendAllTx(addr, feeLevel) + tx, err = w.buildSpendAllTx(addr, fee) if err != nil { return nil, err } } else { - tx, err = w.buildTx(amount.Int64(), addr, feeLevel, nil) + tx, err = w.buildTx(amount.Int64(), addr, fee, nil) if err != nil { return nil, err } diff --git a/vendor/github.com/OpenBazaar/multiwallet/bitcoincash/sign.go b/vendor/github.com/OpenBazaar/multiwallet/bitcoincash/sign.go index b7d88dba13..794f056d45 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/bitcoincash/sign.go +++ b/vendor/github.com/OpenBazaar/multiwallet/bitcoincash/sign.go @@ -30,7 +30,7 @@ import ( "github.com/OpenBazaar/multiwallet/util" ) -func (w *BitcoinCashWallet) buildTx(amount int64, addr btc.Address, feeLevel wi.FeeLevel, optionalOutput *wire.TxOut) (*wire.MsgTx, error) { +func (w *BitcoinCashWallet) buildTx(amount int64, addr btc.Address, fee wi.Fee, optionalOutput *wire.TxOut) (*wire.MsgTx, error) { // Check for dust script, _ := bchutil.PayToAddrScript(addr) if txrules.IsDustAmount(btc.Amount(amount), len(script), txrules.DefaultRelayFeePerKb) { @@ -88,8 +88,17 @@ func (w *BitcoinCashWallet) buildTx(amount int64, addr btc.Address, feeLevel wi. } // Get the fee per kilobyte - f := w.GetFeePerByte(feeLevel) - feePerKB := f.Int64() * 1000 + var feePerKB int64 + if fee.CustomFee != "" { + cf, err := strconv.Atoi(fee.CustomFee) + if err != nil { + return nil, err + } + feePerKB = int64(cf) * 1000 + } else { + f := w.GetFeePerByte(fee.FeeLevel) + feePerKB = f.Int64() * 1000 + } // outputs out := wire.NewTxOut(amount, script) @@ -139,7 +148,7 @@ func (w *BitcoinCashWallet) buildTx(amount int64, addr btc.Address, feeLevel wi. return authoredTx.Tx, nil } -func (w *BitcoinCashWallet) buildSpendAllTx(addr btc.Address, feeLevel wi.FeeLevel) (*wire.MsgTx, error) { +func (w *BitcoinCashWallet) buildSpendAllTx(addr btc.Address, fee wi.Fee) (*wire.MsgTx, error) { tx := wire.NewMsgTx(1) height, _ := w.ws.ChainTip() @@ -158,18 +167,28 @@ func (w *BitcoinCashWallet) buildSpendAllTx(addr btc.Address, feeLevel wi.FeeLev } // Get the fee - fee0 := w.GetFeePerByte(feeLevel) - feePerByte := fee0.Int64() + var feePerByte int64 + if fee.CustomFee != "" { + cf, err := strconv.Atoi(fee.CustomFee) + if err != nil { + return nil, err + } + feePerByte = int64(cf) + } else { + fee0 := w.GetFeePerByte(fee.FeeLevel) + feePerByte = fee0.Int64() + } + estimatedSize := EstimateSerializeSize(1, []*wire.TxOut{wire.NewTxOut(0, script)}, false, P2PKH) - fee := int64(estimatedSize) * feePerByte + feeCost := int64(estimatedSize) * feePerByte // Check for dust output - if txrules.IsDustAmount(btc.Amount(totalIn-fee), len(script), txrules.DefaultRelayFeePerKb) { + if txrules.IsDustAmount(btc.Amount(totalIn-feeCost), len(script), txrules.DefaultRelayFeePerKb) { return nil, wi.ErrorDustAmount } // Build the output - out := wire.NewTxOut(totalIn-fee, script) + out := wire.NewTxOut(totalIn-feeCost, script) tx.TxOut = append(tx.TxOut, out) // BIP 69 sorting @@ -657,7 +676,10 @@ func (w *BitcoinCashWallet) estimateSpendFee(amount int64, feeLevel wi.FeeLevel) if err != nil { return 0, err } - tx, err := w.buildTx(amount, addr, feeLevel, nil) + fee := wi.Fee{ + FeeLevel: feeLevel, + } + tx, err := w.buildTx(amount, addr, fee, nil) if err != nil { return 0, err } diff --git a/vendor/github.com/OpenBazaar/multiwallet/bitcoincash/wallet.go b/vendor/github.com/OpenBazaar/multiwallet/bitcoincash/wallet.go index 99328ce5a4..0e434cc7f6 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/bitcoincash/wallet.go +++ b/vendor/github.com/OpenBazaar/multiwallet/bitcoincash/wallet.go @@ -283,18 +283,19 @@ func (w *BitcoinCashWallet) GetFeePerByte(feeLevel wi.FeeLevel) big.Int { return *big.NewInt(int64(w.fp.GetFeePerByte(feeLevel))) } -func (w *BitcoinCashWallet) Spend(amount big.Int, addr btcutil.Address, feeLevel wi.FeeLevel, referenceID string, spendAll bool) (*chainhash.Hash, error) { +func (w *BitcoinCashWallet) Spend(amount big.Int, addr btcutil.Address, fee wi.Fee, referenceID string, spendAll bool) (*chainhash.Hash, error) { var ( tx *wire.MsgTx err error ) if spendAll { - tx, err = w.buildSpendAllTx(addr, feeLevel) + + tx, err = w.buildSpendAllTx(addr, fee) if err != nil { return nil, err } } else { - tx, err = w.buildTx(amount.Int64(), addr, feeLevel, nil) + tx, err = w.buildTx(amount.Int64(), addr, fee, nil) if err != nil { return nil, err } diff --git a/vendor/github.com/OpenBazaar/multiwallet/litecoin/sign.go b/vendor/github.com/OpenBazaar/multiwallet/litecoin/sign.go index 8991a42701..107d8ed101 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/litecoin/sign.go +++ b/vendor/github.com/OpenBazaar/multiwallet/litecoin/sign.go @@ -31,7 +31,7 @@ import ( "github.com/OpenBazaar/multiwallet/util" ) -func (w *LitecoinWallet) buildTx(amount int64, addr btc.Address, feeLevel wi.FeeLevel, optionalOutput *wire.TxOut) (*wire.MsgTx, error) { +func (w *LitecoinWallet) buildTx(amount int64, addr btc.Address, fee wi.Fee, optionalOutput *wire.TxOut) (*wire.MsgTx, error) { // Check for dust script, _ := laddr.PayToAddrScript(addr) if txrules.IsDustAmount(ltcutil.Amount(amount), len(script), txrules.DefaultRelayFeePerKb) { @@ -84,8 +84,17 @@ func (w *LitecoinWallet) buildTx(amount int64, addr btc.Address, feeLevel wi.Fee } // Get the fee per kilobyte - f := w.GetFeePerByte(feeLevel) - feePerKB := f.Int64() * 1000 + var feePerKB int64 + if fee.CustomFee != "" { + cf, err := strconv.Atoi(fee.CustomFee) + if err != nil { + return nil, err + } + feePerKB = int64(cf) * 1000 + } else { + f := w.GetFeePerByte(fee.FeeLevel) + feePerKB = f.Int64() * 1000 + } // outputs out := wire.NewTxOut(amount, script) @@ -138,7 +147,7 @@ func (w *LitecoinWallet) buildTx(amount int64, addr btc.Address, feeLevel wi.Fee return authoredTx.Tx, nil } -func (w *LitecoinWallet) buildSpendAllTx(addr btc.Address, feeLevel wi.FeeLevel) (*wire.MsgTx, error) { +func (w *LitecoinWallet) buildSpendAllTx(addr btc.Address, fee wi.Fee) (*wire.MsgTx, error) { tx := wire.NewMsgTx(1) height, _ := w.ws.ChainTip() @@ -157,18 +166,28 @@ func (w *LitecoinWallet) buildSpendAllTx(addr btc.Address, feeLevel wi.FeeLevel) } // Get the fee - fee0 := w.GetFeePerByte(feeLevel) - feePerByte := fee0.Int64() + var feePerByte int64 + if fee.CustomFee != "" { + cf, err := strconv.Atoi(fee.CustomFee) + if err != nil { + return nil, err + } + feePerByte = int64(cf) + } else { + fee0 := w.GetFeePerByte(fee.FeeLevel) + feePerByte = fee0.Int64() + } + estimatedSize := EstimateSerializeSize(1, []*wire.TxOut{wire.NewTxOut(0, script)}, false, P2PKH) - fee := int64(estimatedSize) * feePerByte + feeCost := int64(estimatedSize) * feePerByte // Check for dust output - if txrules.IsDustAmount(ltcutil.Amount(totalIn-fee), len(script), txrules.DefaultRelayFeePerKb) { + if txrules.IsDustAmount(ltcutil.Amount(totalIn-feeCost), len(script), txrules.DefaultRelayFeePerKb) { return nil, wi.ErrorDustAmount } // Build the output - out := wire.NewTxOut(totalIn-fee, script) + out := wire.NewTxOut(totalIn-feeCost, script) tx.TxOut = append(tx.TxOut, out) // BIP 69 sorting @@ -654,7 +673,12 @@ func (w *LitecoinWallet) estimateSpendFee(amount int64, feeLevel wi.FeeLevel) (u if err != nil { return 0, err } - tx, err := w.buildTx(amount, addr, feeLevel, nil) + + fee := wi.Fee{ + FeeLevel: feeLevel, + } + + tx, err := w.buildTx(amount, addr, fee, nil) if err != nil { return 0, err } diff --git a/vendor/github.com/OpenBazaar/multiwallet/litecoin/wallet.go b/vendor/github.com/OpenBazaar/multiwallet/litecoin/wallet.go index 1c264048f9..1032a5ca84 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/litecoin/wallet.go +++ b/vendor/github.com/OpenBazaar/multiwallet/litecoin/wallet.go @@ -295,18 +295,18 @@ func (w *LitecoinWallet) GetFeePerByte(feeLevel wi.FeeLevel) big.Int { return *big.NewInt(int64(w.fp.GetFeePerByte(feeLevel))) } -func (w *LitecoinWallet) Spend(amount big.Int, addr btcutil.Address, feeLevel wi.FeeLevel, referenceID string, spendAll bool) (*chainhash.Hash, error) { +func (w *LitecoinWallet) Spend(amount big.Int, addr btcutil.Address, fee wi.Fee, referenceID string, spendAll bool) (*chainhash.Hash, error) { var ( tx *wire.MsgTx err error ) if spendAll { - tx, err = w.buildSpendAllTx(addr, feeLevel) + tx, err = w.buildSpendAllTx(addr, fee) if err != nil { return nil, err } } else { - tx, err = w.buildTx(amount.Int64(), addr, feeLevel, nil) + tx, err = w.buildTx(amount.Int64(), addr, fee, nil) if err != nil { return nil, err } diff --git a/vendor/github.com/OpenBazaar/multiwallet/zcash/sign.go b/vendor/github.com/OpenBazaar/multiwallet/zcash/sign.go index c5f5a1acb2..e3ddc504df 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/zcash/sign.go +++ b/vendor/github.com/OpenBazaar/multiwallet/zcash/sign.go @@ -45,7 +45,7 @@ const ( branchID = 0x2BB40E60 ) -func (w *ZCashWallet) buildTx(amount int64, addr btc.Address, feeLevel wi.FeeLevel, optionalOutput *wire.TxOut) (*wire.MsgTx, error) { +func (w *ZCashWallet) buildTx(amount int64, addr btc.Address, fee wi.Fee, optionalOutput *wire.TxOut) (*wire.MsgTx, error) { // Check for dust script, err := zaddr.PayToAddrScript(addr) if err != nil { @@ -106,8 +106,17 @@ func (w *ZCashWallet) buildTx(amount int64, addr btc.Address, feeLevel wi.FeeLev } // Get the fee per kilobyte - f := w.GetFeePerByte(feeLevel) - feePerKB := f.Int64() * 1000 + var feePerKB int64 + if fee.CustomFee != "" { + cf, err := strconv.Atoi(fee.CustomFee) + if err != nil { + return nil, err + } + feePerKB = int64(cf) * 1000 + } else { + f := w.GetFeePerByte(fee.FeeLevel) + feePerKB = f.Int64() * 1000 + } // outputs out := wire.NewTxOut(amount, script) @@ -167,7 +176,7 @@ func (w *ZCashWallet) buildTx(amount int64, addr btc.Address, feeLevel wi.FeeLev return authoredTx.Tx, nil } -func (w *ZCashWallet) buildSpendAllTx(addr btc.Address, feeLevel wi.FeeLevel) (*wire.MsgTx, error) { +func (w *ZCashWallet) buildSpendAllTx(addr btc.Address, fee wi.Fee) (*wire.MsgTx, error) { tx := wire.NewMsgTx(1) height, _ := w.ws.ChainTip() @@ -186,18 +195,28 @@ func (w *ZCashWallet) buildSpendAllTx(addr btc.Address, feeLevel wi.FeeLevel) (* } // Get the fee - fee0 := w.GetFeePerByte(feeLevel) - feePerByte := fee0.Int64() + var feePerByte int64 + if fee.CustomFee != "" { + cf, err := strconv.Atoi(fee.CustomFee) + if err != nil { + return nil, err + } + feePerByte = int64(cf) + } else { + f := w.GetFeePerByte(fee.FeeLevel) + feePerByte = f.Int64() + } + estimatedSize := EstimateSerializeSize(1, []*wire.TxOut{wire.NewTxOut(0, script)}, false, P2PKH) - fee := int64(estimatedSize) * feePerByte + feeCost := int64(estimatedSize) * feePerByte // Check for dust output - if txrules.IsDustAmount(btc.Amount(totalIn-fee), len(script), txrules.DefaultRelayFeePerKb) { + if txrules.IsDustAmount(btc.Amount(totalIn-feeCost), len(script), txrules.DefaultRelayFeePerKb) { return nil, wi.ErrorDustAmount } // Build the output - out := wire.NewTxOut(totalIn-fee, script) + out := wire.NewTxOut(totalIn-feeCost, script) tx.TxOut = append(tx.TxOut, out) // BIP 69 sorting @@ -608,7 +627,10 @@ func (w *ZCashWallet) estimateSpendFee(amount int64, feeLevel wi.FeeLevel) (uint if err != nil { return 0, err } - tx, err := w.buildTx(amount, addr, feeLevel, nil) + fee := wi.Fee{ + FeeLevel: feeLevel, + } + tx, err := w.buildTx(amount, addr, fee, nil) if err != nil { return 0, err } diff --git a/vendor/github.com/OpenBazaar/multiwallet/zcash/wallet.go b/vendor/github.com/OpenBazaar/multiwallet/zcash/wallet.go index 3cf2a12c07..9207c4fe24 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/zcash/wallet.go +++ b/vendor/github.com/OpenBazaar/multiwallet/zcash/wallet.go @@ -295,18 +295,18 @@ func (w *ZCashWallet) GetFeePerByte(feeLevel wi.FeeLevel) big.Int { return *big.NewInt(int64(w.fp.GetFeePerByte(feeLevel))) } -func (w *ZCashWallet) Spend(amount big.Int, addr btcutil.Address, feeLevel wi.FeeLevel, referenceID string, spendAll bool) (*chainhash.Hash, error) { +func (w *ZCashWallet) Spend(amount big.Int, addr btcutil.Address, fee wi.Fee, referenceID string, spendAll bool) (*chainhash.Hash, error) { var ( tx *wire.MsgTx err error ) if spendAll { - tx, err = w.buildSpendAllTx(addr, feeLevel) + tx, err = w.buildSpendAllTx(addr, fee) if err != nil { return nil, err } } else { - tx, err = w.buildTx(amount.Int64(), addr, feeLevel, nil) + tx, err = w.buildTx(amount.Int64(), addr, fee, nil) if err != nil { return nil, err } diff --git a/vendor/github.com/OpenBazaar/spvwallet/sortsignsend.go b/vendor/github.com/OpenBazaar/spvwallet/sortsignsend.go index 1947afcc3d..c8634bf6d2 100644 --- a/vendor/github.com/OpenBazaar/spvwallet/sortsignsend.go +++ b/vendor/github.com/OpenBazaar/spvwallet/sortsignsend.go @@ -102,18 +102,18 @@ func (w *SPVWallet) gatherCoins() map[coinset.Coin]*hd.ExtendedKey { return m } -func (w *SPVWallet) Spend(amount big.Int, addr btc.Address, feeLevel wallet.FeeLevel, referenceID string, spendAll bool) (*chainhash.Hash, error) { +func (w *SPVWallet) Spend(amount big.Int, addr btc.Address, fee wallet.Fee, referenceID string, spendAll bool) (*chainhash.Hash, error) { var ( tx *wire.MsgTx err error ) if spendAll { - tx, err = w.buildSpendAllTx(addr, feeLevel) + tx, err = w.buildSpendAllTx(addr, fee) if err != nil { return nil, err } } else { - tx, err = w.buildTx(amount.Int64(), addr, feeLevel, nil) + tx, err = w.buildTx(amount.Int64(), addr, fee, nil) if err != nil { return nil, err } @@ -245,7 +245,10 @@ func (w *SPVWallet) EstimateSpendFee(amount big.Int, feeLevel wallet.FeeLevel) ( if err != nil { return *big.NewInt(0), err } - tx, err := w.buildTx(amount.Int64(), addr, feeLevel, nil) + fee := wallet.Fee{ + FeeLevel: feeLevel, + } + tx, err := w.buildTx(amount.Int64(), addr, fee, nil) if err != nil { return *big.NewInt(0), err } @@ -609,7 +612,7 @@ func (w *SPVWallet) SweepAddress(ins []wallet.TransactionInput, address *btc.Add return &txid, nil } -func (w *SPVWallet) buildTx(amount int64, addr btc.Address, feeLevel wallet.FeeLevel, optionalOutput *wire.TxOut) (*wire.MsgTx, error) { +func (w *SPVWallet) buildTx(amount int64, addr btc.Address, fee wallet.Fee, optionalOutput *wire.TxOut) (*wire.MsgTx, error) { // Check for dust script, _ := txscript.PayToAddrScript(addr) if isTxSizeDust(*big.NewInt(amount), len(script)) { @@ -657,8 +660,17 @@ func (w *SPVWallet) buildTx(amount int64, addr btc.Address, feeLevel wallet.FeeL } // Get the fee per kilobyte - f := w.GetFeePerByte(feeLevel) - feePerKB := f.Int64() * 1000 + var feePerKB int64 + if fee.CustomFee != "" { + customFee, err := strconv.Atoi(fee.CustomFee) + if err != nil { + return nil, err + } + feePerKB = int64(customFee * 1000) + } else { + f := w.GetFeePerByte(fee.FeeLevel) + feePerKB = f.Int64() * 1000 + } // outputs out := wire.NewTxOut(amount, script) @@ -708,7 +720,7 @@ func (w *SPVWallet) buildTx(amount int64, addr btc.Address, feeLevel wallet.FeeL return authoredTx.Tx, nil } -func (w *SPVWallet) buildSpendAllTx(addr btc.Address, feeLevel wallet.FeeLevel) (*wire.MsgTx, error) { +func (w *SPVWallet) buildSpendAllTx(addr btc.Address, fee wallet.Fee) (*wire.MsgTx, error) { tx := wire.NewMsgTx(1) coinMap := w.gatherCoins() @@ -745,17 +757,28 @@ func (w *SPVWallet) buildSpendAllTx(addr btc.Address, feeLevel wallet.FeeLevel) } // Get the fee - feePerByte := w.GetFeePerByte(feeLevel) + var feePerByte int64 + if fee.CustomFee != "" { + cf, err := strconv.Atoi(fee.CustomFee) + if err != nil { + return nil, err + } + feePerByte = int64(cf) + } else { + f := w.GetFeePerByte(fee.FeeLevel) + feePerByte = f.Int64() + } + estimatedSize := EstimateSerializeSize(1, []*wire.TxOut{wire.NewTxOut(0, script)}, false, P2PKH) - fee := int64(estimatedSize) * feePerByte.Int64() + feeAmount := int64(estimatedSize) * feePerByte // Check for dust output - if isTxSizeDust(*big.NewInt(totalIn - fee), len(script)) { + if isTxSizeDust(*big.NewInt(totalIn - feeAmount), len(script)) { return nil, wallet.ErrorDustAmount } // Build the output - out := wire.NewTxOut(totalIn-fee, script) + out := wire.NewTxOut(totalIn-feeAmount, script) tx.TxOut = append(tx.TxOut, out) // BIP 69 sorting diff --git a/vendor/github.com/OpenBazaar/wallet-interface/wallet.go b/vendor/github.com/OpenBazaar/wallet-interface/wallet.go index a60985c715..5a9278ca1d 100644 --- a/vendor/github.com/OpenBazaar/wallet-interface/wallet.go +++ b/vendor/github.com/OpenBazaar/wallet-interface/wallet.go @@ -238,7 +238,7 @@ type walletMustBanker interface { // be swept to the provided payment address. For most coins this entails subtracting the // transaction fee from the total amount being sent rather than adding it on as is normally // the case when spendAll is false. - Spend(amount big.Int, addr btc.Address, feeLevel FeeLevel, referenceID string, spendAll bool) (*chainhash.Hash, error) + Spend(amount big.Int, addr btc.Address, fee Fee, referenceID string, spendAll bool) (*chainhash.Hash, error) // EstimateFee should return the estimate fee that will be required to make a transaction // spending from the given inputs to the given outputs. FeePerByte is denominated in @@ -288,8 +288,14 @@ const ( ECONOMIC = 2 FEE_BUMP = 3 SUPER_ECONOMIC = 4 + CUSTOM = 5 ) +type Fee struct { + FeeLevel FeeLevel + CustomFee string +} + // The end leaves on the HD wallet have only two possible values. External keys are those given // to other people for the purpose of receiving transactions. These may include keys used for // refund addresses. Internal keys are used only by the wallet, primarily for change addresses