Skip to content

Commit 56b14df

Browse files
committed
use erc20 contractor for token contract gas estimates
1 parent eb16ea9 commit 56b14df

8 files changed

Lines changed: 74 additions & 69 deletions

File tree

client/asset/eth/contractor.go

Lines changed: 36 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ func (c *contractorV0) estimateInitGas(ctx context.Context, n int) (uint64, erro
361361
func (c *contractorV0) estimateGas(ctx context.Context, value *big.Int, method string, args ...any) (uint64, error) {
362362
data, err := c.abi.Pack(method, args...)
363363
if err != nil {
364-
return 0, fmt.Errorf("Pack error: %v", err)
364+
return 0, fmt.Errorf("pack error: %v", err)
365365
}
366366

367367
return c.cb.EstimateGas(ctx, ethereum.CallMsg{
@@ -424,34 +424,36 @@ func (c *contractorV0) outgoingValue(tx *types.Transaction) (swapped uint64) {
424424

425425
// erc20Contractor supports the ERC20 ABI. Embedded in token contractors.
426426
type erc20Contractor struct {
427-
tokenContract *erc20.IERC20
428-
acct common.Address
429-
contract common.Address
427+
cb bind.ContractBackend
428+
tokenContract *erc20.IERC20
429+
tokenAddr common.Address
430+
acctAddr common.Address
431+
swapContractAddr common.Address
430432
}
431433

432434
// balance exposes the read-only balanceOf method of the erc20 token contract.
433435
func (c *erc20Contractor) balance(ctx context.Context) (*big.Int, error) {
434436
callOpts := &bind.CallOpts{
435-
From: c.acct,
437+
From: c.acctAddr,
436438
Context: ctx,
437439
}
438440

439-
return c.tokenContract.BalanceOf(callOpts, c.acct)
441+
return c.tokenContract.BalanceOf(callOpts, c.acctAddr)
440442
}
441443

442444
// allowance exposes the read-only allowance method of the erc20 token contract.
443445
func (c *erc20Contractor) allowance(ctx context.Context) (*big.Int, error) {
444446
callOpts := &bind.CallOpts{
445-
From: c.acct,
447+
From: c.acctAddr,
446448
Context: ctx,
447449
}
448-
return c.tokenContract.Allowance(callOpts, c.acct, c.contract)
450+
return c.tokenContract.Allowance(callOpts, c.acctAddr, c.swapContractAddr)
449451
}
450452

451453
// approve sends an approve transaction approving the linked contract to call
452454
// transferFrom for the specified amount.
453455
func (c *erc20Contractor) approve(txOpts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error) {
454-
return c.tokenContract.Approve(txOpts, c.contract, amount)
456+
return c.tokenContract.Approve(txOpts, c.swapContractAddr, amount)
455457
}
456458

457459
// transfer calls the transfer method of the erc20 token contract. Used for
@@ -460,12 +462,22 @@ func (c *erc20Contractor) transfer(txOpts *bind.TransactOpts, addr common.Addres
460462
return c.tokenContract.Transfer(txOpts, addr, amount)
461463
}
462464

465+
// estimateApproveGas estimates the gas needed to send an approve tx.
466+
func (c *erc20Contractor) estimateApproveGas(ctx context.Context, amount *big.Int) (uint64, error) {
467+
return estimateGas(ctx, c.acctAddr, c.tokenAddr, erc20.ERC20ABI, c.cb, new(big.Int), "approve", c.swapContractAddr, amount)
468+
}
469+
470+
// estimateTransferGas estimates the gas needed for a transfer tx. The account
471+
// needs to have > amount tokens to use this method.
472+
func (c *erc20Contractor) estimateTransferGas(ctx context.Context, amount *big.Int) (uint64, error) {
473+
return estimateGas(ctx, c.acctAddr, c.swapContractAddr, erc20.ERC20ABI, c.cb, new(big.Int), "transfer", c.acctAddr, amount)
474+
}
475+
463476
// tokenContractorV0 is a contractor that implements the tokenContractor
464477
// methods, providing access to the methods of the token's ERC20 contract.
465478
type tokenContractorV0 struct {
466479
*contractorV0
467480
*erc20Contractor
468-
tokenAddr common.Address
469481
}
470482

471483
var _ contractor = (*tokenContractorV0)(nil)
@@ -514,32 +526,17 @@ func newV0TokenContractor(net dex.Network, token *dexeth.Token, acctAddr common.
514526
evmify: token.AtomicToEVM,
515527
atomize: token.EVMToAtomic,
516528
},
517-
tokenAddr: tokenAddr,
529+
518530
erc20Contractor: &erc20Contractor{
519-
tokenContract: tokenContract,
520-
acct: acctAddr,
521-
contract: swapContractAddr,
531+
cb: cb,
532+
tokenContract: tokenContract,
533+
tokenAddr: tokenAddr,
534+
acctAddr: acctAddr,
535+
swapContractAddr: swapContractAddr,
522536
},
523537
}, nil
524538
}
525539

526-
// estimateApproveGas estimates the gas needed to send an approve tx.
527-
func (c *tokenContractorV0) estimateApproveGas(ctx context.Context, amount *big.Int) (uint64, error) {
528-
return c.estimateGas(ctx, "approve", c.contractAddr, amount)
529-
}
530-
531-
// estimateTransferGas esimates the gas needed for a transfer tx. The account
532-
// needs to have > amount tokens to use this method.
533-
func (c *tokenContractorV0) estimateTransferGas(ctx context.Context, amount *big.Int) (uint64, error) {
534-
return c.estimateGas(ctx, "transfer", c.acctAddr, amount)
535-
}
536-
537-
// estimateGas estimates the gas needed for methods on the ERC20 token contract.
538-
// For estimating methods on the swap contract, use (contractorV0).estimateGas.
539-
func (c *tokenContractorV0) estimateGas(ctx context.Context, method string, args ...interface{}) (uint64, error) {
540-
return estimateGas(ctx, c.acctAddr, c.contractAddr, c.abi, c.cb, new(big.Int), method, args...)
541-
}
542-
543540
// value finds incoming or outgoing value for the tx to either the swap contract
544541
// or the erc20 token contract. For the token contract, only transfer and
545542
// transferFrom are parsed. It is not an error if this tx is a call to another
@@ -555,7 +552,7 @@ func (c *tokenContractorV0) value(ctx context.Context, tx *types.Transaction) (i
555552

556553
// Consider removing. We'll never be sending transferFrom transactions
557554
// directly.
558-
if sender, _, value, err := erc20.ParseTransferFromData(tx.Data()); err == nil && sender == c.acctAddr {
555+
if sender, _, value, err := erc20.ParseTransferFromData(tx.Data()); err == nil && sender == c.contractorV0.acctAddr {
559556
return 0, c.atomize(value), nil
560557
}
561558

@@ -827,7 +824,6 @@ func (c *contractorV1) value(ctx context.Context, tx *types.Transaction) (in, ou
827824
type tokenContractorV1 struct {
828825
*contractorV1
829826
*erc20Contractor
830-
tokenAddr common.Address
831827
}
832828

833829
func newV1TokenContractor(net dex.Network, token *dexeth.Token, acctAddr common.Address, cb bind.ContractBackend) (tokenContractor, error) {
@@ -871,30 +867,17 @@ func newV1TokenContractor(net dex.Network, token *dexeth.Token, acctAddr common.
871867
evmify: token.AtomicToEVM,
872868
atomize: token.EVMToAtomic,
873869
},
874-
tokenAddr: tokenAddr,
870+
875871
erc20Contractor: &erc20Contractor{
876-
tokenContract: tokenContract,
877-
acct: acctAddr,
878-
contract: swapContractAddr,
872+
cb: cb,
873+
tokenContract: tokenContract,
874+
tokenAddr: tokenAddr,
875+
acctAddr: acctAddr,
876+
swapContractAddr: swapContractAddr,
879877
},
880878
}, nil
881879
}
882880

883-
// estimateApproveGas estimates the gas needed to send an approve tx.
884-
func (c *tokenContractorV1) estimateApproveGas(ctx context.Context, amount *big.Int) (uint64, error) {
885-
return c.estimateTokenContractGas(ctx, "approve", c.contractAddr, amount)
886-
}
887-
888-
// estimateTransferGas estimates the gas needed for a transfer tx. The account
889-
// needs to have > amount tokens to use this method.
890-
func (c *tokenContractorV1) estimateTransferGas(ctx context.Context, amount *big.Int) (uint64, error) {
891-
return c.estimateTokenContractGas(ctx, "transfer", c.acctAddr, amount)
892-
}
893-
894-
func (c *tokenContractorV1) estimateTokenContractGas(ctx context.Context, method string, args ...interface{}) (uint64, error) {
895-
return estimateGas(ctx, c.acctAddr, c.tokenAddr, erc20.ERC20ABI, c.cb, new(big.Int), method, args...)
896-
}
897-
898881
// value finds incoming or outgoing value for the tx to either the swap contract
899882
// or the erc20 token contract. For the token contract, only transfer and
900883
// transferFrom are parsed. It is not an error if this tx is a call to another
@@ -910,7 +893,7 @@ func (c *tokenContractorV1) value(ctx context.Context, tx *types.Transaction) (i
910893

911894
// Consider removing. We'll never be sending transferFrom transactions
912895
// directly.
913-
if sender, _, value, err := erc20.ParseTransferFromData(tx.Data()); err == nil && sender == c.acctAddr {
896+
if sender, _, value, err := erc20.ParseTransferFromData(tx.Data()); err == nil && sender == c.contractorV1.acctAddr {
914897
return 0, c.atomize(value), nil
915898
}
916899

client/asset/eth/eth.go

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,6 @@ const (
121121
// unverified on-chain before we halt broadcasting of new txs.
122122
maxUnindexedTxs = 10
123123
peerCountTicker = 5 * time.Second // no rpc calls here
124-
125-
contractVersionERC20 = ^uint32(0)
126-
contractVersionUnknown = contractVersionERC20 - 1
127124
)
128125

129126
var (
@@ -4352,7 +4349,7 @@ func (w *ETHWallet) sendToAddr(addr common.Address, amt uint64, maxFeeRate, tipR
43524349

43534350
// sendToAddr sends funds to the address.
43544351
func (w *TokenWallet) sendToAddr(addr common.Address, amt uint64, maxFeeRate, tipRate *big.Int) (tx *types.Transaction, err error) {
4355-
g := w.gases(contractVersionERC20)
4352+
g := w.gases(dexeth.ContractVersionERC20)
43564353
if g == nil {
43574354
return nil, fmt.Errorf("no gas table")
43584355
}
@@ -4365,7 +4362,7 @@ func (w *TokenWallet) sendToAddr(addr common.Address, amt uint64, maxFeeRate, ti
43654362
if addr == w.addr {
43664363
txType = asset.SelfSend
43674364
}
4368-
return tx, txType, amt, w.withTokenContractor(w.assetID, contractVersionERC20, func(c tokenContractor) error {
4365+
return tx, txType, amt, w.withTokenContractor(w.assetID, dexeth.ContractVersionERC20, func(c tokenContractor) error {
43694366
tx, err = c.transfer(txOpts, addr, w.evmify(amt))
43704367
if err != nil {
43714368
return err
@@ -6149,7 +6146,7 @@ func getGasEstimates(ctx context.Context, cl, acl ethFetcher, c contractor, ac t
61496146
if err = checkTxStatus(receipt, txOpts.GasLimit); err != nil {
61506147
return fmt.Errorf("init tx failed status check: %w", err)
61516148
}
6152-
log.Infof("%d gas used for %d initiation txs", receipt.GasUsed, n)
6149+
log.Infof("%d gas used for %d initiations in tx %s", receipt.GasUsed, n, tx.Hash())
61536150
stats.swaps = append(stats.swaps, receipt.GasUsed)
61546151

61556152
// Estimate a refund
@@ -6177,7 +6174,7 @@ func getGasEstimates(ctx context.Context, cl, acl ethFetcher, c contractor, ac t
61776174
if err != nil {
61786175
return fmt.Errorf("error constructing signed tx opts for %d redeems: %v", n, err)
61796176
}
6180-
log.Debugf("Sending %d redemption txs", n)
6177+
log.Debugf("Sending %d redemptions", n)
61816178
tx, err = c.redeem(txOpts, redemptions)
61826179
if err != nil {
61836180
return fmt.Errorf("redeem error for %d swaps: %v", n, err)
@@ -6192,7 +6189,7 @@ func getGasEstimates(ctx context.Context, cl, acl ethFetcher, c contractor, ac t
61926189
if err = checkTxStatus(receipt, txOpts.GasLimit); err != nil {
61936190
return fmt.Errorf("redeem tx failed status check: %w", err)
61946191
}
6195-
log.Infof("%d gas used for %d redemptions", receipt.GasUsed, n)
6192+
log.Infof("%d gas used for %d redemptions in tx %s", receipt.GasUsed, n, tx.Hash())
61966193
stats.redeems = append(stats.redeems, receipt.GasUsed)
61976194
}
61986195

client/asset/eth/nodeclient_harness_test.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2048,8 +2048,6 @@ func testRefund(t *testing.T, assetID uint32) {
20482048
t.Fatalf("unexpected swap state for test %v: want %s got %s", test.name, dexeth.SSNone, status.Step)
20492049
}
20502050

2051-
inLocktime := uint64(time.Now().Add(test.addTime).Unix())
2052-
20532051
txOpts, err := ethClient.txOpts(ctx, optsVal, gases.SwapN(1), nil, nil, nil)
20542052
if err != nil {
20552053
t.Fatalf("%s: txOpts error: %v", test.name, err)

dex/networks/eth/tokens.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -336,13 +336,13 @@ func MaybeReadSimnetAddrsDir(
336336
return
337337
}
338338

339-
ethSwapContractAddrFileV0 := filepath.Join(harnessDir, "eth_swap_contract_address.txt")
340-
testUSDCSwapContractAddrFileV0 := filepath.Join(harnessDir, "usdc_swap_contract_address.txt")
339+
ethSwapContractAddrFileV0 := filepath.Join(harnessDir, "eth_swap_contract_address_v0.txt")
340+
ethSwapContractAddrFileV1 := filepath.Join(harnessDir, "eth_swap_contract_address_v1.txt")
341+
testUSDCSwapContractAddrFileV0 := filepath.Join(harnessDir, "usdc_swap_contract_address_v0.txt")
342+
testUSDCSwapContractAddrFileV1 := filepath.Join(harnessDir, "usdc_swap_contract_address_v1.txt")
341343
testUSDCContractAddrFile := filepath.Join(harnessDir, "test_usdc_contract_address.txt")
342344
testUSDTSwapContractAddrFileV0 := filepath.Join(harnessDir, "usdt_swap_contract_address.txt")
343345
testUSDTContractAddrFile := filepath.Join(harnessDir, "test_usdt_contract_address.txt")
344-
ethSwapContractAddrFileV1 := filepath.Join(harnessDir, "eth_swap_contract_address_v1.txt")
345-
testUSDCSwapContractAddrFileV1 := filepath.Join(harnessDir, "usdc_swap_contract_address_v1.txt")
346346
multiBalanceContractAddrFile := filepath.Join(harnessDir, "multibalance_address.txt")
347347

348348
contractAddrs[0][dex.Simnet] = maybeGetContractAddrFromFile(ethSwapContractAddrFileV0)

dex/testing/dcrdex/harness.sh

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,17 @@ tmux kill-session -t $SESSION
124124
EOF
125125
chmod +x "${DCRDEX_DATA_DIR}/quit"
126126

127+
cat > "${DCRDEX_DATA_DIR}/evm-protocol-overrides.json" <<EOF
128+
{
129+
"usdt.eth": 0,
130+
"polygon": 0,
131+
"usdc.polygon": 0,
132+
"usdt.polygon": 0,
133+
"weth.polygon": 0,
134+
"wbtc.polygon": 0
135+
}
136+
EOF
137+
127138
cat > "${DCRDEX_DATA_DIR}/run" <<EOF
128139
#!/usr/bin/env bash
129140
${HARNESS_DIR}/genmarkets.sh

dex/testing/eth/harness.sh

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ PASSWORD="abc"
5454
export NODES_ROOT=~/dextest/eth
5555
export GENESIS_JSON_FILE_LOCATION="${NODES_ROOT}/genesis.json"
5656

57+
# Ensure we can create the session and that there's not a session already
58+
# running before we nuke the data directory.
59+
tmux new-session -d -s $SESSION "${SHELL}"
60+
5761
if [ -d "${NODES_ROOT}" ]; then
5862
rm -R "${NODES_ROOT}"
5963
fi
@@ -234,8 +238,6 @@ chmod +x "${NODES_ROOT}/harness-ctl/quit"
234238
# Start harness
235239
################################################################################
236240

237-
echo "Starting harness"
238-
tmux new-session -d -s $SESSION "${SHELL}"
239241
tmux rename-window -t $SESSION:0 'harness-ctl'
240242
tmux send-keys -t $SESSION:0 "set +o history" C-m
241243
tmux send-keys -t $SESSION:0 "cd ${NODES_ROOT}/harness-ctl" C-m

server/asset/eth/eth.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,18 @@ func (d *Driver) Setup(cfg *asset.BackendConfig) (asset.Backend, error) {
184184
chainID = 42
185185
}
186186

187+
for _, tkn := range registeredTokens {
188+
netToken, found := tkn.NetTokens[cfg.Net]
189+
if !found {
190+
return nil, fmt.Errorf("no %s token for %s", tkn.Name, cfg.Net)
191+
}
192+
if _, found = netToken.SwapContracts[tkn.ContractVersion]; !found {
193+
return nil, fmt.Errorf("no version %d swap contract adddress for %s on %s. "+
194+
"Do you need a version override in evm-protocol-overrides.json?",
195+
tkn.ContractVersion, tkn.Name, cfg.Net)
196+
}
197+
}
198+
187199
return NewEVMBackend(cfg, chainID, dexeth.ContractAddresses, registeredTokens)
188200
}
189201

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
{
22
"eth": 0,
33
"usdc.eth": 0,
4+
"usdt.eth": 0,
45
"polygon": 0,
56
"usdc.polygon": 0,
7+
"usdt.polygon": 0,
68
"wbtc.polygon": 0,
79
"weth.polygon": 0
810
}

0 commit comments

Comments
 (0)