fix: set GasLimit for relayed transactions (#425)

Co-authored-by: Dmitry Holodov <dimalinux@protonmail.com>
This commit is contained in:
noot
2023-04-26 21:55:46 +02:00
committed by GitHub
parent caa5251e59
commit c1d5347616
6 changed files with 64 additions and 17 deletions

View File

@@ -60,7 +60,7 @@ func (h *Host) handleRelayStream(stream libp2pnetwork.Stream) {
// (2) If the request is purportedly from a maker to a taker of a current
// swap, then:
// (a) The swap should exist in our swaps map
// (b) The peerID who sent us the request much match the peerID with
// (b) The peerID who sent us the request must match the peerID with
// whom we are performing the swap.
if req.OfferID == nil && !h.isRelayer {
return
@@ -120,7 +120,7 @@ func receiveRelayClaimResponse(stream libp2pnetwork.Stream) (*RelayClaimResponse
// The timeout should be short enough, that the Maker can try multiple relayers
// before T1 expires even if the receiving node accepts the relay request and
// just sits on it without doing anything.
const relayResponseTimeout = time.Second * 45
const relayResponseTimeout = time.Minute
select {
case msg := <-nextStreamMessage(stream, maxMessageSize):

View File

@@ -7,6 +7,7 @@ import (
"context"
"errors"
"fmt"
"math/big"
"time"
"github.com/ethereum/go-ethereum"
@@ -15,9 +16,11 @@ import (
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/athanorlabs/atomic-swap/coins"
"github.com/athanorlabs/atomic-swap/common"
"github.com/athanorlabs/atomic-swap/common/types"
"github.com/athanorlabs/atomic-swap/ethereum/block"
"github.com/athanorlabs/atomic-swap/ethereum/extethclient"
"github.com/athanorlabs/atomic-swap/net/message"
"github.com/athanorlabs/atomic-swap/relayer"
)
@@ -39,12 +42,16 @@ func (s *swapState) claimFunds() (*ethtypes.Receipt, error) {
log.Infof("balance before claim: %s %s", balance.AsStandardString(), balance.StandardSymbol())
}
hasBalanceToClaim, err := checkForMinClaimBalance(s.ctx, s.ETHClient())
if err != nil {
return nil, err
}
var receipt *ethtypes.Receipt
// call swap.Swap.Claim() w/ b.privkeys.sk, revealing XMRMaker's secret spend key
if s.offerExtra.UseRelayer || weiBalance.Decimal().IsZero() {
if s.offerExtra.UseRelayer || !hasBalanceToClaim {
// relayer fee was set or we had insufficient funds to claim without a relayer
// TODO: Sufficient funds check above should be more specific
receipt, err = s.claimWithRelay()
if err != nil {
return nil, fmt.Errorf("failed to claim using relayers: %w", err)
@@ -81,6 +88,40 @@ func (s *swapState) claimFunds() (*ethtypes.Receipt, error) {
return receipt, nil
}
// checkForMinClaimBalance check if we have enough balance to call claim.
// return true if we do, false otherwise.
func checkForMinClaimBalance(ctx context.Context, ec extethclient.EthClient) (bool, error) {
// gas cost for ETH-claim is 42965
// gas cost for ERC20-claim is 47138
// add a bit of leeway to allow for sudden gas price spikes
const claimGas = 50000
balance, err := ec.Balance(ctx)
if err != nil {
return false, err
}
if balance.Decimal().IsZero() {
return false, nil
}
gasPrice, err := ec.SuggestGasPrice(ctx)
if err != nil {
return false, err
}
txCost := new(big.Int).Mul(gasPrice, big.NewInt(claimGas))
if balance.BigInt().Cmp(txCost) < 0 {
log.Infof("balance %s ETH is under the minimum %s ETH to call claim, using a relayer",
balance.AsEtherString(),
coins.FmtWeiAsETH(txCost),
)
return false, nil
}
return true, nil
}
// relayClaimWithXMRTaker relays the claim to the swap's XMR taker, who should
// process the claim even if they are not relaying claims for everyone.
func (s *swapState) relayClaimWithXMRTaker(request *message.RelayClaimRequest) (*ethtypes.Receipt, error) {
@@ -106,7 +147,6 @@ func (s *swapState) relayClaimWithXMRTaker(request *message.RelayClaimRequest) (
}
log.Infof("relayer's claim via counterparty included and validated %s", common.ReceiptInfo(receipt))
return receipt, nil
}
@@ -128,6 +168,7 @@ func (s *swapState) claimWithAdvertisedRelayers(request *message.RelayClaimReque
log.Debugf("skipping DHT-advertised relayer that is our swap counterparty")
continue
}
log.Debugf("submitting claim to relayer with peer ID %s", relayerPeerID)
resp, err := s.Backend.SubmitClaimToRelayer(relayerPeerID, request)
if err != nil {

View File

@@ -196,16 +196,9 @@ func (s *swapState) handleEvent(event Event) {
err := s.handleNotifyETHLocked(e.message)
if err != nil {
e.errCh <- fmt.Errorf("failed to handle EventETHLocked: %w", err)
if !s.fundsLocked {
return
}
}
err = s.setNextExpectedEvent(EventContractReadyType)
if err != nil {
e.errCh <- fmt.Errorf("failed to set next expected event to EventContractReadyType: %w", err)
return
}
// nextExpectedEvent was set in s.lockFunds()
case *EventContractReady:
log.Infof("EventContractReady")
defer close(e.errCh)

View File

@@ -77,8 +77,6 @@ type swapState struct {
// tracks the state of the swap
nextExpectedEvent EventType
// set to true once funds are locked
fundsLocked bool
readyWatcher *watcher.EventFilter
@@ -654,8 +652,15 @@ func (s *swapState) lockFunds(amount *coins.PiconeroAmount) error {
log.Debug("total XMR balance: ", coins.FmtPiconeroAsXMR(balance.Balance))
log.Info("unlocked XMR balance: ", coins.FmtPiconeroAsXMR(balance.UnlockedBalance))
log.Infof("Starting lock of %s XMR in address %s", amount.AsMoneroString(), swapDestAddr)
// set next expected event here, otherwise if we restart while `Transfer` is happening,
// we won't notice that we already locked the XMR on restart.
err = s.setNextExpectedEvent(EventContractReadyType)
if err != nil {
return fmt.Errorf("failed to set next expected event to EventContractReadyType: %w", err)
}
transfer, err := s.XMRClient().Transfer(s.ctx, swapDestAddr, 0, amount, monero.MinSpendConfirmations)
if err != nil {
return err
@@ -663,6 +668,5 @@ func (s *swapState) lockFunds(amount *coins.PiconeroAmount) error {
log.Infof("Successfully locked XMR funds: txID=%s address=%s block=%d",
transfer.TxID, swapDestAddr, transfer.Height)
s.fundsLocked = true
return nil
}

View File

@@ -117,5 +117,11 @@ func (s *swapState) claimMonero(skB *mcrypto.PrivateSpendKey) (*mcrypto.Address,
close(s.claimedCh)
log.Infof("monero claimed and swept to original account %s", depositAddr)
go func() {
err = s.Exit()
if err != nil {
log.Warnf("failed to exit: %v", err)
}
}()
return kpAB.PublicKeyPair().Address(s.Env()), nil
}

View File

@@ -78,6 +78,8 @@ func ValidateAndSendTransaction(
return nil, err
}
txOpts.GasPrice = gasPrice
txOpts.GasLimit = forwarderClaimGas
log.Debugf("relaying tx with gas price %s and gas limit %d", gasPrice, txOpts.GasLimit)
err = simulateExecute(
ctx,
@@ -101,6 +103,7 @@ func ValidateAndSendTransaction(
req.Signature,
)
if err != nil {
log.Errorf("failed to call execute: %s", err)
return nil, err
}