Skip to content

Commit

Permalink
Binance Withdrawals
Browse files Browse the repository at this point in the history
  • Loading branch information
martonp committed Oct 7, 2023
1 parent f389639 commit b6a9a56
Show file tree
Hide file tree
Showing 28 changed files with 1,733 additions and 273 deletions.
12 changes: 6 additions & 6 deletions client/asset/btc/btc.go
Original file line number Diff line number Diff line change
Expand Up @@ -4895,23 +4895,23 @@ func (btc *baseWallet) EstimateRegistrationTxFee(feeRate uint64) uint64 {
// Withdraw withdraws funds to the specified address. Fees are subtracted from
// the value. feeRate is in units of sats/byte.
// Withdraw satisfies asset.Withdrawer.
func (btc *baseWallet) Withdraw(address string, value, feeRate uint64) (asset.Coin, error) {
func (btc *baseWallet) Withdraw(address string, value, feeRate uint64) (string, asset.Coin, error) {
txHash, vout, sent, err := btc.send(address, value, btc.feeRateWithFallback(feeRate), true)
if err != nil {
return nil, err
return "", nil, err
}
return newOutput(txHash, vout, sent), nil
return txHash.String(), newOutput(txHash, vout, sent), nil
}

// Send sends the exact value to the specified address. This is different from
// Withdraw, which subtracts the tx fees from the amount sent. feeRate is in
// units of sats/byte.
func (btc *baseWallet) Send(address string, value, feeRate uint64) (asset.Coin, error) {
func (btc *baseWallet) Send(address string, value, feeRate uint64) (string, asset.Coin, error) {
txHash, vout, sent, err := btc.send(address, value, btc.feeRateWithFallback(feeRate), false)
if err != nil {
return nil, err
return "", nil, err
}
return newOutput(txHash, vout, sent), nil
return txHash.String(), newOutput(txHash, vout, sent), nil
}

// SendTransaction broadcasts a valid fully-signed transaction.
Expand Down
6 changes: 3 additions & 3 deletions client/asset/btc/btc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3725,11 +3725,11 @@ func testSender(t *testing.T, senderType tSenderType, segwit bool, walletType st
wallet, node, shutdown := tNewWallet(segwit, walletType)
defer shutdown()
const feeSuggestion = 100
sender := func(addr string, val uint64) (asset.Coin, error) {
sender := func(addr string, val uint64) (string, asset.Coin, error) {
return wallet.Send(addr, val, defaultFee)
}
if senderType == tWithdrawSender {
sender = func(addr string, val uint64) (asset.Coin, error) {
sender = func(addr string, val uint64) (string, asset.Coin, error) {
return wallet.Withdraw(addr, val, feeSuggestion)
}
}
Expand Down Expand Up @@ -3894,7 +3894,7 @@ func testSender(t *testing.T, senderType tSenderType, segwit bool, walletType st
node.listUnspent = test.unspents
wallet.bondReserves.Store(test.bondReserves)

_, err := sender(addr.String(), test.val)
_, _, err := sender(addr.String(), test.val)
if test.expectErr {
if err == nil {
t.Fatalf("%s: no error for expected error", test.name)
Expand Down
4 changes: 2 additions & 2 deletions client/asset/btc/livetest/livetest.go
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,7 @@ func Run(t *testing.T, cfg *Config) {

// Test Send.
tLogger.Info("Testing Send")
coin, err := rig.secondWallet.Send(address, cfg.LotSize, defaultFee)
_, coin, err := rig.secondWallet.Send(address, cfg.LotSize, defaultFee)
if err != nil {
t.Fatalf("error sending: %v", err)
}
Expand All @@ -573,7 +573,7 @@ func Run(t *testing.T, cfg *Config) {
// Test Withdraw.
withdrawer, _ := rig.secondWallet.Wallet.(asset.Withdrawer)
tLogger.Info("Testing Withdraw")
coin, err = withdrawer.Withdraw(address, cfg.LotSize, defaultFee)
_, coin, err = withdrawer.Withdraw(address, cfg.LotSize, defaultFee)
if err != nil {
t.Fatalf("error withdrawing: %v", err)
}
Expand Down
16 changes: 8 additions & 8 deletions client/asset/dcr/dcr.go
Original file line number Diff line number Diff line change
Expand Up @@ -4301,31 +4301,31 @@ func (dcr *ExchangeWallet) SendTransaction(rawTx []byte) ([]byte, error) {
// Withdraw withdraws funds to the specified address. Fees are subtracted from
// the value. feeRate is in units of atoms/byte.
// Withdraw satisfies asset.Withdrawer.
func (dcr *ExchangeWallet) Withdraw(address string, value, feeRate uint64) (asset.Coin, error) {
func (dcr *ExchangeWallet) Withdraw(address string, value, feeRate uint64) (string, asset.Coin, error) {
addr, err := stdaddr.DecodeAddress(address, dcr.chainParams)
if err != nil {
return nil, fmt.Errorf("invalid address: %s", address)
return "", nil, fmt.Errorf("invalid address: %s", address)
}
msgTx, sentVal, err := dcr.withdraw(addr, value, dcr.feeRateWithFallback(feeRate))
if err != nil {
return nil, err
return "", nil, err
}
return newOutput(msgTx.CachedTxHash(), 0, sentVal, wire.TxTreeRegular), nil
return msgTx.CachedTxHash().String(), newOutput(msgTx.CachedTxHash(), 0, sentVal, wire.TxTreeRegular), nil
}

// Send sends the exact value to the specified address. This is different from
// Withdraw, which subtracts the tx fees from the amount sent. feeRate is in
// units of atoms/byte.
func (dcr *ExchangeWallet) Send(address string, value, feeRate uint64) (asset.Coin, error) {
func (dcr *ExchangeWallet) Send(address string, value, feeRate uint64) (string, asset.Coin, error) {
addr, err := stdaddr.DecodeAddress(address, dcr.chainParams)
if err != nil {
return nil, fmt.Errorf("invalid address: %s", address)
return "", nil, fmt.Errorf("invalid address: %s", address)
}
msgTx, sentVal, err := dcr.sendToAddress(addr, value, dcr.feeRateWithFallback(feeRate))
if err != nil {
return nil, err
return "", nil, err
}
return newOutput(msgTx.CachedTxHash(), 0, sentVal, wire.TxTreeRegular), nil
return msgTx.CachedTxHash().String(), newOutput(msgTx.CachedTxHash(), 0, sentVal, wire.TxTreeRegular), nil
}

// ValidateSecret checks that the secret satisfies the contract.
Expand Down
12 changes: 6 additions & 6 deletions client/asset/dcr/dcr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3361,14 +3361,14 @@ func testSender(t *testing.T, senderType tSenderType) {
var unspentVal uint64 = 100e8
const feeSuggestion = 100
funName := "Send"
sender := func(addr string, val uint64) (asset.Coin, error) {
sender := func(addr string, val uint64) (string, asset.Coin, error) {
return wallet.Send(addr, val, feeSuggestion)
}
if senderType == tWithdrawSender {
funName = "Withdraw"
// For withdraw, test with unspent total = withdraw value
unspentVal = sendVal
sender = func(addr string, val uint64) (asset.Coin, error) {
sender = func(addr string, val uint64) (string, asset.Coin, error) {
return wallet.Withdraw(addr, val, feeSuggestion)
}
}
Expand All @@ -3387,29 +3387,29 @@ func testSender(t *testing.T, senderType tSenderType) {
}}
//node.unspent = append(node.unspent, node.unspent[0])

_, err := sender(addr, sendVal)
_, _, err := sender(addr, sendVal)
if err != nil {
t.Fatalf(funName+" error: %v", err)
}

// invalid address
_, err = sender("badaddr", sendVal)
_, _, err = sender("badaddr", sendVal)
if err == nil {
t.Fatalf("no error for bad address: %v", err)
}

// GetRawChangeAddress error
if senderType == tSendSender { // withdraw test does not get a change address
node.changeAddrErr = tErr
_, err = sender(addr, sendVal)
_, _, err = sender(addr, sendVal)
if err == nil {
t.Fatalf("no error for rawchangeaddress: %v", err)
}
node.changeAddrErr = nil
}

// good again
_, err = sender(addr, sendVal)
_, _, err = sender(addr, sendVal)
if err != nil {
t.Fatalf(funName+" error afterwards: %v", err)
}
Expand Down
20 changes: 10 additions & 10 deletions client/asset/eth/eth.go
Original file line number Diff line number Diff line change
Expand Up @@ -3136,14 +3136,14 @@ func (w *assetWallet) SwapConfirmations(ctx context.Context, coinID dex.Bytes, c

// Send sends the exact value to the specified address. The provided fee rate is
// ignored since all sends will use an internally derived fee rate.
func (w *ETHWallet) Send(addr string, value, _ uint64) (asset.Coin, error) {
func (w *ETHWallet) Send(addr string, value, _ uint64) (string, asset.Coin, error) {
if err := isValidSend(addr, value, false); err != nil {
return nil, err
return "", nil, err
}

maxFee, maxFeeRate, err := w.canSend(value, true, false)
if err != nil {
return nil, err
return "", nil, err
}
// TODO: Subtract option.
// if avail < value+maxFee {
Expand All @@ -3152,37 +3152,37 @@ func (w *ETHWallet) Send(addr string, value, _ uint64) (asset.Coin, error) {

tx, err := w.sendToAddr(common.HexToAddress(addr), value, maxFeeRate)
if err != nil {
return nil, err
return "", nil, err
}

txHash := tx.Hash()
w.addToTxHistory(tx.Nonce(), -int64(value), maxFee, 0, w.assetID, txHash[:], asset.Send)

return &coin{id: txHash, value: value}, nil
return txHash.String(), &coin{id: txHash, value: value}, nil
}

// Send sends the exact value to the specified address. Fees are taken from the
// parent wallet. The provided fee rate is ignored since all sends will use an
// internally derived fee rate.
func (w *TokenWallet) Send(addr string, value, _ uint64) (asset.Coin, error) {
func (w *TokenWallet) Send(addr string, value, _ uint64) (string, asset.Coin, error) {
if err := isValidSend(addr, value, false); err != nil {
return nil, err
return "", nil, err
}

maxFee, maxFeeRate, err := w.canSend(value, true, false)
if err != nil {
return nil, err
return "", nil, err
}

tx, err := w.sendToAddr(common.HexToAddress(addr), value, maxFeeRate)
if err != nil {
return nil, err
return "", nil, err
}

txHash := tx.Hash()
w.addToTxHistory(tx.Nonce(), -int64(value), maxFee, 0, w.assetID, txHash[:], asset.Send)

return &coin{id: txHash, value: value}, nil
return txHash.String(), &coin{id: txHash, value: value}, nil
}

// ValidateSecret checks that the secret satisfies the contract.
Expand Down
6 changes: 3 additions & 3 deletions client/asset/eth/eth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4340,7 +4340,7 @@ func testSend(t *testing.T, assetID uint32) {
node.tokenContractor.bal = dexeth.GweiToWei(val - test.sendAdj)
node.bal = dexeth.GweiToWei(tokenFees - test.feeAdj)
}
coin, err := w.Send(test.addr, val, 0)
_, coin, err := w.Send(test.addr, val, 0)
if test.wantErr {
if err == nil {
t.Fatalf("expected error for test %v", test.name)
Expand Down Expand Up @@ -5253,15 +5253,15 @@ func testEstimateVsActualSendFees(t *testing.T, assetID uint32) {
if err != nil {
t.Fatalf("error converting canSend to gwei: %v", err)
}
_, err = w.Send(testAddr, canSendGwei, 0)
_, _, err = w.Send(testAddr, canSendGwei, 0)
if err != nil {
t.Fatalf("error sending: %v", err)
}
} else {
tokenVal := uint64(10e9)
node.tokenContractor.bal = dexeth.GweiToWei(tokenVal)
node.bal = dexeth.GweiToWei(fee)
_, err = w.Send(testAddr, tokenVal, 0)
_, _, err = w.Send(testAddr, tokenVal, 0)
if err != nil {
t.Fatalf("error sending: %v", err)
}
Expand Down
4 changes: 2 additions & 2 deletions client/asset/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,7 @@ type Wallet interface {
RegFeeConfirmations(ctx context.Context, coinID dex.Bytes) (confs uint32, err error)
// Send sends the exact value to the specified address. This is different
// from Withdraw, which subtracts the tx fees from the amount sent.
Send(address string, value, feeRate uint64) (Coin, error)
Send(address string, value, feeRate uint64) (txID string, coin Coin, err error)
// EstimateRegistrationTxFee returns an estimate for the tx fee needed to
// pay the registration fee using the provided feeRate.
EstimateRegistrationTxFee(feeRate uint64) uint64
Expand Down Expand Up @@ -629,7 +629,7 @@ type Recoverer interface {
type Withdrawer interface {
// Withdraw withdraws funds to the specified address. Fees are subtracted
// from the value.
Withdraw(address string, value, feeRate uint64) (Coin, error)
Withdraw(address string, value, feeRate uint64) (txID string, coin Coin, err error)
}

// Sweeper is a wallet that can clear the entire balance of the wallet/account
Expand Down
51 changes: 26 additions & 25 deletions client/core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -4295,7 +4295,7 @@ func (c *Core) Register(form *RegisterForm) (*RegisterResult, error) {
"Do NOT manually send funds to this address even if this fails.",
regRes.Address, dc.acct.id, regRes.Fee, regFeeAssetSymbol)
feeRate := c.feeSuggestionAny(feeAsset.ID, dc)
coin, err := wallet.Send(regRes.Address, regRes.Fee, feeRate)
_, coin, err := wallet.Send(regRes.Address, regRes.Fee, feeRate)
if err != nil {
return nil, newError(feeSendErr, "error paying registration fee: %w", err)
}
Expand Down Expand Up @@ -5341,62 +5341,63 @@ func (c *Core) feeSuggestion(dc *dexConnection, assetID uint32) (feeSuggestion u
return dc.fetchFeeRate(assetID)
}

// Withdraw initiates a withdraw from an exchange wallet. The client password
// must be provided as an additional verification. This method is DEPRECATED. Use
// Send with the subtract option instead.
func (c *Core) Withdraw(pw []byte, assetID uint32, value uint64, address string) (asset.Coin, error) {
return c.Send(pw, assetID, value, address, true)
}

// Send initiates either send or withdraw from an exchange wallet. if subtract
// is true, fees are subtracted from the value else fees are taken from the
// exchange wallet. The client password must be provided as an additional
// verification.
func (c *Core) Send(pw []byte, assetID uint32, value uint64, address string, subtract bool) (asset.Coin, error) {
crypter, err := c.encryptionKey(pw)
if err != nil {
return nil, fmt.Errorf("password error: %w", err)
// exchange wallet.
func (c *Core) Send(pw []byte, assetID uint32, value uint64, address string, subtract bool) (string, asset.Coin, error) {
var crypter encrypt.Crypter
// Empty password can be provided if wallet is already unlocked. Webserver
// and RPCServer should not allow empty password, but this is used for
// bots.
if len(pw) > 0 {
var err error
crypter, err = c.encryptionKey(pw)
if err != nil {
return "", nil, fmt.Errorf("Trade password error: %w", err)
}
defer crypter.Close()
}
defer crypter.Close()

if value == 0 {
return nil, fmt.Errorf("cannot send/withdraw zero %s", unbip(assetID))
return "", nil, fmt.Errorf("cannot send/withdraw zero %s", unbip(assetID))
}
wallet, found := c.wallet(assetID)
if !found {
return nil, newError(missingWalletErr, "no wallet found for %s", unbip(assetID))
return "", nil, newError(missingWalletErr, "no wallet found for %s", unbip(assetID))
}
err = c.connectAndUnlock(crypter, wallet)
err := c.connectAndUnlock(crypter, wallet)
if err != nil {
return nil, err
return "", nil, err
}

if err = wallet.checkPeersAndSyncStatus(); err != nil {
return nil, err
return "", nil, err
}

var coin asset.Coin
var txID string
feeSuggestion := c.feeSuggestionAny(assetID)
if !subtract {
coin, err = wallet.Wallet.Send(address, value, feeSuggestion)
txID, coin, err = wallet.Wallet.Send(address, value, feeSuggestion)
} else {
if withdrawer, isWithdrawer := wallet.Wallet.(asset.Withdrawer); isWithdrawer {
coin, err = withdrawer.Withdraw(address, value, feeSuggestion)
txID, coin, err = withdrawer.Withdraw(address, value, feeSuggestion)
} else {
return nil, fmt.Errorf("wallet does not support subtracting network fee from withdraw amount")
return "", nil, fmt.Errorf("wallet does not support subtracting network fee from withdraw amount")
}
}
if err != nil {
subject, details := c.formatDetails(TopicSendError, unbip(assetID), err)
c.notify(newSendNote(TopicSendError, subject, details, db.ErrorLevel))
return nil, err
return "", nil, err
}

sentValue := wallet.Info().UnitInfo.ConventionalString(coin.Value())
subject, details := c.formatDetails(TopicSendSuccess, sentValue, unbip(assetID), address, coin)
c.notify(newSendNote(TopicSendSuccess, subject, details, db.Success))

c.updateAssetBalance(assetID)
return coin, nil
return txID, coin, nil
}

// ValidateAddress checks that the provided address is valid.
Expand Down
Loading

0 comments on commit b6a9a56

Please sign in to comment.