@@ -30,7 +30,6 @@ import (
3030 "decred.org/dcrdex/dex/config"
3131 "decred.org/dcrdex/dex/encode"
3232 "decred.org/dcrdex/dex/keygen"
33- "decred.org/dcrdex/dex/networks/erc20"
3433 dexeth "decred.org/dcrdex/dex/networks/eth"
3534 "github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa"
3635 "github.com/decred/dcrd/hdkeychain/v3"
@@ -60,7 +59,8 @@ func registerToken(tokenID uint32, desc string, nets ...dex.Network) {
6059func init () {
6160 asset .Register (BipID , & Driver {})
6261 // Test token
63- registerToken (testTokenID , "A token wallet for the DEX test token. Used for testing DEX software." , dex .Simnet )
62+ registerToken (simnetTokenID , "A token wallet for the DEX test token. Used for testing DEX software." , dex .Simnet )
63+ registerToken (usdcTokenID , "The USDC Ethereum ERC20 token." , dex .Testnet )
6464}
6565
6666const (
@@ -83,7 +83,8 @@ const (
8383)
8484
8585var (
86- testTokenID , _ = dex .BipSymbolID ("dextt.eth" )
86+ simnetTokenID , _ = dex .BipSymbolID ("dextt.eth" )
87+ usdcTokenID , _ = dex .BipSymbolID ("usdc.eth" )
8788 // blockTicker is the delay between calls to check for new blocks.
8889 blockTicker = time .Second
8990 peerCountTicker = 5 * time .Second
@@ -1482,7 +1483,7 @@ func (w *assetWallet) approvalGas(newGas *big.Int, ver uint32) (uint64, error) {
14821483 if approveEst , err := w .estimateApproveGas (newGas ); err != nil {
14831484 return 0 , fmt .Errorf ("error estimating approve gas: %v" , err )
14841485 } else if approveEst > approveGas {
1485- w .log .Warnf ("Approve gas estimate %d is greater than the expected value %d. Using live estimate + 10%." )
1486+ w .log .Warnf ("Approve gas estimate %d is greater than the expected value %d. Using live estimate + 10%%." , approveEst , approveGas )
14861487 return approveEst * 11 / 10 , nil
14871488 }
14881489 return approveGas , nil
@@ -1756,6 +1757,14 @@ func (w *TokenWallet) Swap(swaps *asset.Swaps) ([]asset.Receipt, asset.Coin, uin
17561757 return fail ("Swap: initiate error: %w" , err )
17571758 }
17581759
1760+ if dexeth .Tokens [w .assetID ] == nil ||
1761+ dexeth .Tokens [w .assetID ].NetTokens [w .net ] == nil ||
1762+ dexeth .Tokens [w .assetID ].NetTokens [w .net ].SwapContracts [swaps .Version ] == nil {
1763+ return fail ("unable to find contract address for asset %d" , w .assetID )
1764+ }
1765+
1766+ contractAddr := dexeth .Tokens [w .assetID ].NetTokens [w .net ].SwapContracts [swaps .Version ].Address .String ()
1767+
17591768 txHash := tx .Hash ()
17601769 for _ , swap := range swaps .Contracts {
17611770 var secretHash [dexeth .SecretHashSize ]byte
@@ -1766,7 +1775,7 @@ func (w *TokenWallet) Swap(swaps *asset.Swaps) ([]asset.Receipt, asset.Coin, uin
17661775 txHash : txHash ,
17671776 secretHash : secretHash ,
17681777 ver : swaps .Version ,
1769- contractAddr : erc20. ContractAddresses [swaps. Version ][w. net ]. String () ,
1778+ contractAddr : contractAddr ,
17701779 })
17711780 }
17721781
@@ -2039,11 +2048,13 @@ func (w *assetWallet) approveToken(amount *big.Int, maxFeeRate uint64, contractV
20392048
20402049 return tx , w .withTokenContractor (w .assetID , contractVer , func (c tokenContractor ) error {
20412050 tx , err = c .approve (txOpts , amount )
2042- if err = = nil {
2043- w . log . Infof ( "Approval sent for %s at token address %s, nonce = %s" ,
2044- dex . BipIDSymbol ( w . assetID ), c . tokenAddress (), txOpts . Nonce )
2051+ if err ! = nil {
2052+ c . voidUnusedNonce ()
2053+ return err
20452054 }
2046- return err
2055+ w .log .Infof ("Approval sent for %s at token address %s, nonce = %s" ,
2056+ dex .BipIDSymbol (w .assetID ), c .tokenAddress (), txOpts .Nonce )
2057+ return nil
20472058 })
20482059}
20492060
@@ -3387,7 +3398,7 @@ func (w *assetWallet) confirmRedemption(coinID dex.Bytes, redemption *asset.Rede
33873398
33883399 monitoredTx , err := w .getLatestMonitoredTx (txHash )
33893400 if err != nil {
3390- w .log .Error ("getLatestMonitoredTx error: %v" , err )
3401+ w .log .Errorf ("getLatestMonitoredTx error: %v" , err )
33913402 return w .confirmRedemptionWithoutMonitoredTx (txHash , redemption , feeWallet )
33923403 }
33933404 // This mutex is locked inside of getLatestMonitoredTx.
@@ -3571,7 +3582,14 @@ func (w *ETHWallet) sendToAddr(addr common.Address, amt uint64, maxFeeRate *big.
35713582 if err != nil {
35723583 return nil , err
35733584 }
3574- return w .node .sendTransaction (w .ctx , txOpts , addr , nil )
3585+ tx , err = w .node .sendTransaction (w .ctx , txOpts , addr , nil )
3586+ if err != nil {
3587+ if mRPC , is := w .node .(* multiRPCClient ); is {
3588+ mRPC .voidUnusedNonce ()
3589+ }
3590+ return nil , err
3591+ }
3592+ return tx , nil
35753593}
35763594
35773595// sendToAddr sends funds to the address.
@@ -3588,7 +3606,11 @@ func (w *TokenWallet) sendToAddr(addr common.Address, amt uint64, maxFeeRate *bi
35883606 return err
35893607 }
35903608 tx , err = c .transfer (txOpts , addr , w .evmify (amt ))
3591- return err
3609+ if err != nil {
3610+ c .voidUnusedNonce ()
3611+ return err
3612+ }
3613+ return nil
35923614 })
35933615}
35943616
@@ -3612,10 +3634,17 @@ func (w *assetWallet) initiate(ctx context.Context, assetID uint32, contracts []
36123634 }
36133635 w .nonceSendMtx .Lock ()
36143636 defer w .nonceSendMtx .Unlock ()
3615- txOpts , _ := w .node .txOpts (ctx , val , gasLimit , dexeth .GweiToWei (maxFeeRate ))
3637+ txOpts , err := w .node .txOpts (ctx , val , gasLimit , dexeth .GweiToWei (maxFeeRate ))
3638+ if err != nil {
3639+ return nil , err
3640+ }
36163641 return tx , w .withContractor (contractVer , func (c contractor ) error {
36173642 tx , err = c .initiate (txOpts , contracts )
3618- return err
3643+ if err != nil {
3644+ c .voidUnusedNonce ()
3645+ return err
3646+ }
3647+ return nil
36193648 })
36203649}
36213650
@@ -3740,7 +3769,11 @@ func (w *assetWallet) redeem(ctx context.Context, assetID uint32, redemptions []
37403769
37413770 return tx , w .withContractor (contractVer , func (c contractor ) error {
37423771 tx , err = c .redeem (txOpts , redemptions )
3743- return err
3772+ if err != nil {
3773+ c .voidUnusedNonce ()
3774+ return err
3775+ }
3776+ return nil
37443777 })
37453778}
37463779
@@ -3756,12 +3789,16 @@ func (w *assetWallet) refund(secretHash [32]byte, maxFeeRate uint64, contractVer
37563789 defer w .nonceSendMtx .Unlock ()
37573790 txOpts , err := w .node .txOpts (w .ctx , 0 , gas .Refund , dexeth .GweiToWei (maxFeeRate ))
37583791 if err != nil {
3759- return nil , fmt . Errorf ( "addSignerToOpts error: %w" , err )
3792+ return nil , err
37603793 }
37613794
37623795 return tx , w .withContractor (contractVer , func (c contractor ) error {
37633796 tx , err = c .refund (txOpts , secretHash )
3764- return err
3797+ if err != nil {
3798+ c .voidUnusedNonce ()
3799+ return err
3800+ }
3801+ return nil
37653802 })
37663803}
37673804
@@ -3799,7 +3836,8 @@ func checkTxStatus(receipt *types.Receipt, gasLimit uint64) error {
37993836// factor of 2. The account should already have a trading balance of at least
38003837// maxSwaps gwei (token or eth), and sufficient eth balance to cover the
38013838// requisite tx fees.
3802- func GetGasEstimates (ctx context.Context , cl ethFetcher , c contractor , maxSwaps int , g * dexeth.Gases , waitForMined func ()) error {
3839+ func GetGasEstimates (ctx context.Context , cl ethFetcher , c contractor , maxSwaps int , g * dexeth.Gases ,
3840+ toAddress common.Address , waitForMined func (), waitForReceipt func (ethFetcher , * types.Transaction ) (* types.Receipt , error )) error {
38033841 tokenContractor , isToken := c .(tokenContractor )
38043842
38053843 stats := struct {
@@ -3872,7 +3910,7 @@ func GetGasEstimates(ctx context.Context, cl ethFetcher, c contractor, maxSwaps
38723910 if err != nil {
38733911 return fmt .Errorf ("error constructing signed tx opts for transfer: %v" , err )
38743912 }
3875- transferTx , err = tokenContractor .transfer (txOpts , cl . address () , big .NewInt (1 ))
3913+ transferTx , err = tokenContractor .transfer (txOpts , toAddress , big .NewInt (1 ))
38763914 if err != nil {
38773915 return fmt .Errorf ("error estimating transfer gas: %v" , err )
38783916 }
@@ -3909,7 +3947,7 @@ func GetGasEstimates(ctx context.Context, cl ethFetcher, c contractor, maxSwaps
39093947 return fmt .Errorf ("initiate error for %d swaps: %v" , n , err )
39103948 }
39113949 waitForMined ()
3912- receipt , _ , err := cl . transactionReceipt ( ctx , tx . Hash () )
3950+ receipt , err := waitForReceipt ( cl , tx )
39133951 if err != nil {
39143952 return err
39153953 }
@@ -3919,15 +3957,15 @@ func GetGasEstimates(ctx context.Context, cl ethFetcher, c contractor, maxSwaps
39193957 stats .swaps = append (stats .swaps , receipt .GasUsed )
39203958
39213959 if isToken {
3922- receipt , _ , err = cl . transactionReceipt ( ctx , approveTx . Hash () )
3960+ receipt , err = waitForReceipt ( cl , approveTx )
39233961 if err != nil {
39243962 return err
39253963 }
39263964 if err := checkTxStatus (receipt , txOpts .GasLimit ); err != nil {
39273965 return err
39283966 }
39293967 stats .approves = append (stats .approves , receipt .GasUsed )
3930- receipt , _ , err = cl . transactionReceipt ( ctx , transferTx . Hash () )
3968+ receipt , err = waitForReceipt ( cl , transferTx )
39313969 if err != nil {
39323970 return err
39333971 }
@@ -3962,7 +4000,7 @@ func GetGasEstimates(ctx context.Context, cl ethFetcher, c contractor, maxSwaps
39624000 return fmt .Errorf ("redeem error for %d swaps: %v" , n , err )
39634001 }
39644002 waitForMined ()
3965- receipt , _ , err = cl . transactionReceipt ( ctx , tx . Hash () )
4003+ receipt , err = waitForReceipt ( cl , tx )
39664004 if err != nil {
39674005 return err
39684006 }
0 commit comments