diff --git a/ethergo/submitter/submitter.go b/ethergo/submitter/submitter.go index 3e7d9443f4..735b1db129 100644 --- a/ethergo/submitter/submitter.go +++ b/ethergo/submitter/submitter.go @@ -8,6 +8,7 @@ import ( "math/big" "reflect" "runtime" + "strings" "sync" "time" @@ -388,9 +389,6 @@ func (t *txSubmitterImpl) SubmitTransaction(parentCtx context.Context, chainID * // this also prevents a bug in the caller from breaking our lock transactor.Nonce = new(big.Int).Add(new(big.Int).SetUint64(math.MaxUint64), big.NewInt(1)) - //tmpdebug - fmt.Printf("SubmitTransaction>setGasPrice\n") - err = t.setGasPrice(ctx, chainClient, transactor, chainID, nil) if err != nil { span.AddEvent("could not set gas price", trace.WithAttributes(attribute.String("error", err.Error()))) @@ -422,64 +420,59 @@ func (t *txSubmitterImpl) SubmitTransaction(parentCtx context.Context, chainID * return parentTransactor.Signer(address, transaction) } - //tmpdebug - fmt.Printf("test ver 7\n") - // if dynamic gas estimation is not enabled, use cfg var gas_estimate as a gas limit default and do not run a pre-flight simulation // since we do not need it to determine proper gas units if !t.config.GetDynamicGasEstimate(int(chainID.Uint64())) { - - //tmpdebug - fmt.Printf("Using Default \n") - transactor.GasLimit = t.config.GetGasEstimate(int(chainID.Uint64())) } else { - // //tmpdebug - // fmt.Printf("SubmitTransaction>forGasEst call \n") + // deepcopy the real transactor so we can use it for simulation + transactor_forGasEstimate := copyTransactOpts(transactor) - // transactor_forGasEstimate := copyTransactOpts(transactor) + // override the signer func for our simulation/estimation with a version that does not lock the nonce, + // which would othewrise cause a deadlock with the following *actual* transactor + transactor_forGasEstimate.Signer = func(address common.Address, transaction *types.Transaction) (_ *types.Transaction, err error) { - // transactor_forGasEstimate.Nonce.Add(transactor_forGasEstimate.Nonce, big.NewInt(1)) + newNonce, err := t.getNonce(ctx, chainID, address) + if err != nil { + return nil, fmt.Errorf("could not sign tx: %w", err) + } - // tx_forGasEstimate, err := call(transactor_forGasEstimate) - // if err != nil { - // return 0, fmt.Errorf("err contract call for gas est: %w", err) - // } + txType := t.txTypeForChain(chainID) - // fmt.Printf("tx_forGasEstimate: %v\n", tx_forGasEstimate.Gas()) + transaction, err = util.CopyTX(transaction, util.WithNonce(newNonce), util.WithTxType(txType)) + if err != nil { + return nil, fmt.Errorf("could not copy tx: %w", err) + } - //transactor.GasLimit = tx_forGasEstimate.Gas() + 555 + //nolint: wrapcheck + return parentTransactor.Signer(address, transaction) + } + + tx_forGasEstimate, err := call(transactor_forGasEstimate) + if err != nil { + // at the moment, omniRPC gives a massive HTML doc w/ many sim errors.. reduce the noise. + errMsg := err.Error() + if strings.Contains(errMsg, "") { + errMsg = strings.Split(errMsg, "")[0] + "" + } - // if arbitrum, spoof some low gas units to induce bump tests - if chainID.Uint64() == 10 { - transactor.GasLimit = 0 - } else if chainID.Uint64() == 42161 { - transactor.GasLimit = 200000 + return 0, fmt.Errorf("err contract call for gas est: %s", errMsg) } - } - //tmpdebug - fmt.Printf("transactor.GasLimit: %d\n", transactor.GasLimit) + // with our gas limit now obtained from the simulation, apply this limit (plus any configured % modifier) to the + // gas limit of the actual transactor that is about to prepare the real transaction + gasLimitAddPercentage := t.config.GetDynamicGasUnitAddPercentage(int(chainID.Uint64())) + transactor.GasLimit = tx_forGasEstimate.Gas() + (tx_forGasEstimate.Gas() * uint64(gasLimitAddPercentage) / 100) + } - var cancel context.CancelFunc - transactor.Context, cancel = context.WithTimeout(ctx, time.Second*5) - defer func() { - cancel() - }() tx, err := call(transactor) if err != nil { return 0, fmt.Errorf("err contract call for tx: %w", err) } - //tmpdebug - fmt.Printf("tx.Gas: %d\n", tx.Gas()) - defer locker.Unlock() - //tmpdebug - fmt.Printf("SubmitTransaction>storeTX\n") - // now that we've stored the tx err = t.storeTX(ctx, tx, db.Stored, uuid.New().String()) if err != nil { @@ -489,9 +482,6 @@ func (t *txSubmitterImpl) SubmitTransaction(parentCtx context.Context, chainID * span.AddEvent("trigger reprocess") t.triggerProcessQueue(ctx) - //tmpdebug - fmt.Printf("SubmitTransaction>tx.Nonce: %d\n", tx.Nonce()) - return tx.Nonce(), nil } @@ -732,31 +722,23 @@ func (t *txSubmitterImpl) getGasBlock(ctx context.Context, chainClient client.EV // getGasEstimate gets the gas estimate for the given transaction. // TODO: handle l2s w/ custom gas pricing through contracts. -func (t *txSubmitterImpl) getGasEstimate(ctx context.Context, chainClient client.EVM, chainID int, tx *types.Transaction) (gasLimit_new uint64, err error) { +func (t *txSubmitterImpl) getGasEstimate(ctx context.Context, chainClient client.EVM, chainID int, tx *types.Transaction) (gasLimit uint64, err error) { // if dynamic gas estimation is not enabled, use cfg var gas_estimate as a default if !t.config.GetDynamicGasEstimate(chainID) { return t.config.GetGasEstimate(chainID), nil } - //tmpdebug - fmt.Println("getGasEstimate>start") - gasUnitAddPercentage := t.config.GetDynamicGasUnitAddPercentage(chainID) - //tmpdebug - fmt.Println("getGasEstimate>gasUnitAddPercentage", gasUnitAddPercentage) - ctx, span := t.metrics.Tracer().Start(ctx, "submitter.getGasEstimate", trace.WithAttributes( attribute.Int(metrics.ChainID, chainID), - attribute.String(metrics.TxHash, tx.Hash().String()), - attribute.Int("gasUnitAddPercentage", gasUnitAddPercentage), )) defer func() { - span.AddEvent("estimated_gas", trace.WithAttributes(attribute.Int64("gas", int64(gasLimit_new)))) + span.AddEvent("estimated_gas", trace.WithAttributes(attribute.Int64("gas", int64(gasLimit)))) metrics.EndSpanWithErr(span, err) }() @@ -766,34 +748,20 @@ func (t *txSubmitterImpl) getGasEstimate(ctx context.Context, chainClient client return 0, fmt.Errorf("could not convert tx to call: %w", err) } - // bump gas limit from prior by X% - gasLimit_fromPrior := tx.Gas() - gasLimit_fromEstimate, err := chainClient.EstimateGas(ctx, *call) if err != nil { - - //tmpdebug - fmt.Printf("getGasEstimate> Error estimating gas: %v\n", err) - span.AddEvent("could not estimate gas", trace.WithAttributes(attribute.String("error", err.Error()))) - // if we failed to est gas for any reason, use *at least* the default flat gas on the next bump - gasLimit_fromEstimate = max(t.config.GetGasEstimate(chainID), gasLimit_fromEstimate) + // if we failed to est gas for any reason, use the default flat gas from config + gasLimit = t.config.GetGasEstimate(chainID) + } else { + // multiply the freshly simulated gasLimit by the configured gas unit add percentage + gasLimit_fromEstimate += (gasLimit_fromEstimate * uint64(gasUnitAddPercentage) / 100) + gasLimit = gasLimit_fromEstimate } - // start with whichever value is higher gas from the prior attempt, or gas from our latest simulation estimate - gasLimit_new = max(gasLimit_fromPrior, gasLimit_fromEstimate) - - // whichever source is used as the base, multiply it by the configured gas unit add percentage - gasLimit_new = gasLimit_new + (gasLimit_new * uint64(gasUnitAddPercentage) / 100) - span.AddEvent("new gas limit", trace.WithAttributes( - attribute.Int64("gas_limit", int64(gasLimit_new)), - attribute.Int64("gas_limit_from_prior", int64(gasLimit_fromPrior)), - attribute.Int64("gas_limit_from_estimate", int64(gasLimit_fromEstimate)), - )) - - return gasLimit_new, nil + return gasLimit, nil } func (t *txSubmitterImpl) Address() common.Address { diff --git a/services/rfq/contracts/fastbridgev2/events.go b/services/rfq/contracts/fastbridgev2/events.go index 2547ebad28..aeff1ee0eb 100644 --- a/services/rfq/contracts/fastbridgev2/events.go +++ b/services/rfq/contracts/fastbridgev2/events.go @@ -20,6 +20,8 @@ var ( BridgeDepositClaimedTopic common.Hash // BridgeProofDisputedTopic is the topic emitted by a bridge dispute. BridgeProofDisputedTopic common.Hash + // BridgeProofDisputedTopic is a secondary topic emitted by a bridge request. + BridgeQuoteDetailsTopic common.Hash ) // static checks to make sure topics actually exist. @@ -67,6 +69,7 @@ func topicMap() map[EventType]common.Hash { BridgeProofProvidedEvent: BridgeProofProvidedTopic, BridgeDepositClaimedEvent: BridgeDepositClaimedTopic, BridgeDisputeEvent: BridgeProofDisputedTopic, + BridgeQuoteDetailsEvent: BridgeQuoteDetailsTopic, } } diff --git a/services/rfq/contracts/fastbridgev2/eventtype_string.go b/services/rfq/contracts/fastbridgev2/eventtype_string.go index b7c65ba096..9fd676f18d 100644 --- a/services/rfq/contracts/fastbridgev2/eventtype_string.go +++ b/services/rfq/contracts/fastbridgev2/eventtype_string.go @@ -13,11 +13,12 @@ func _() { _ = x[BridgeProofProvidedEvent-3] _ = x[BridgeDepositClaimedEvent-4] _ = x[BridgeDisputeEvent-5] + _ = x[BridgeQuoteDetailsEvent-6] } -const _EventType_name = "BridgeRequestedEventBridgeRelayedEventBridgeProofProvidedEventBridgeDepositClaimedEventBridgeDisputeEvent" +const _EventType_name = "BridgeRequestedEventBridgeRelayedEventBridgeProofProvidedEventBridgeDepositClaimedEventBridgeDisputeEventBridgeQuoteDetailsEvent" -var _EventType_index = [...]uint8{0, 20, 38, 62, 87, 105} +var _EventType_index = [...]uint8{0, 20, 38, 62, 87, 105, 127} func (i EventType) String() string { i -= 1 diff --git a/services/rfq/contracts/fastbridgev2/parser.go b/services/rfq/contracts/fastbridgev2/parser.go index 5fe9d66570..4cc4870e31 100644 --- a/services/rfq/contracts/fastbridgev2/parser.go +++ b/services/rfq/contracts/fastbridgev2/parser.go @@ -23,6 +23,8 @@ const ( BridgeDepositClaimedEvent // BridgeDisputeEvent is the event type for the BridgeDispute event. BridgeDisputeEvent + // BridgeQuoteDetailsEvent is emitted along w/ BridgeRequestedEvent as supplemental data + BridgeQuoteDetailsEvent ) // Parser parses events from the fastbridge contracat. @@ -91,6 +93,12 @@ func (p parserImpl) ParseEvent(log ethTypes.Log) (_ EventType, event interface{} return noOpEvent, nil, false } return eventType, disputed, true + case BridgeQuoteDetailsEvent: + quoteDetails, err := p.filterer.ParseBridgeQuoteDetails(log) + if err != nil { + return noOpEvent, nil, false + } + return eventType, quoteDetails, true } return eventType, nil, true diff --git a/services/rfq/relayer/chain/chain.go b/services/rfq/relayer/chain/chain.go index 08f38035eb..7fab137186 100644 --- a/services/rfq/relayer/chain/chain.go +++ b/services/rfq/relayer/chain/chain.go @@ -74,9 +74,6 @@ func (c Chain) SubmitRelay(ctx context.Context, request reldb.QuoteRequest) (uin gasAmount := big.NewInt(0) var err error - //tmpdebug - fmt.Println("SubmitRelay>start: ", request.OriginTxHash) - // Check to see if ETH should be sent to destination if util.IsGasToken(request.Transaction.DestToken) { gasAmount = request.Transaction.DestAmount @@ -89,37 +86,20 @@ func (c Chain) SubmitRelay(ctx context.Context, request reldb.QuoteRequest) (uin } } - //tmpdebug - fmt.Println("SubmitRelay>SubmitTransaction: ", request.OriginTxHash) - nonce, err := c.SubmitTransaction(ctx, func(transactor *bind.TransactOpts) (tx *types.Transaction, err error) { transactor.Value = core.CopyBigInt(gasAmount) - //tmpdebug - callType := "exec" - if transactor.GasLimit == 0 { - callType = "sim" - } - - //tmpdebug - fmt.Println(callType, "SubmitTransaction>RelayV2: ", request.OriginTxHash) - tx, err = c.Bridge.RelayV2(transactor, request.RawRequest, c.submitter.Address()) if err != nil { return nil, fmt.Errorf("could not relay: %w", err) } - //tmpdebug - fmt.Println(callType, "RelayV2 Return tx hash:", request.OriginTxHash, tx.Hash()) - return tx, nil }) if err != nil { return 0, nil, fmt.Errorf("could not submit transaction: %w", err) } - //tmpdebug - fmt.Println("SubmitRelay nonce:", nonce, "gas amount:", gasAmount) return nonce, gasAmount, nil } diff --git a/services/rfq/relayer/pricer/fee_pricer.go b/services/rfq/relayer/pricer/fee_pricer.go index b259497b01..8871b458dc 100644 --- a/services/rfq/relayer/pricer/fee_pricer.go +++ b/services/rfq/relayer/pricer/fee_pricer.go @@ -261,9 +261,17 @@ func (f *feePricer) getZapGasEstimate(ctx context.Context, destination uint32, q callMsg.Value = quoteRequest.Transaction.ZapNative } + // note: this gas amount is intentionally not modified gasEstimate, err = client.EstimateGas(ctx, callMsg) if err != nil { - return 0, fmt.Errorf("could not estimate gas: %w", err) + + // at the moment, omniRPC gives a massive HTML doc w/ many sim errors.. reduce the noise. + errMsg := err.Error() + if strings.Contains(errMsg, "") { + errMsg = strings.Split(errMsg, "")[0] + "" + } + + return 0, fmt.Errorf("could not estimate gas: %s", errMsg) } return gasEstimate, nil diff --git a/services/rfq/relayer/service/handlers.go b/services/rfq/relayer/service/handlers.go index d730b9b612..124cd13527 100644 --- a/services/rfq/relayer/service/handlers.go +++ b/services/rfq/relayer/service/handlers.go @@ -377,9 +377,6 @@ func (q *QuoteRequestHandler) handleCommitPending(ctx context.Context, span trac // TODO: just to be safe, we should probably check if another relayer has already relayed this. func (q *QuoteRequestHandler) handleCommitConfirmed(ctx context.Context, span trace.Span, request reldb.QuoteRequest) (err error) { - //tmpdebug - fmt.Println("handleCommitConfirmed>SubmitRelay: ", request.OriginTxHash) - // TODO: store the dest txhash connected to the nonce nonce, _, err := q.Dest.SubmitRelay(ctx, request) if err != nil { @@ -388,15 +385,11 @@ func (q *QuoteRequestHandler) handleCommitConfirmed(ctx context.Context, span tr span.AddEvent("relay successfully submitted") span.SetAttributes(attribute.Int("relay_nonce", int(nonce))) - //tmpdebug - fmt.Println("handleCommitConfirmed>UpdateQuoteRequestStatus: ", request.OriginTxHash) err = q.db.UpdateQuoteRequestStatus(ctx, request.TransactionID, reldb.RelayStarted, &request.Status) if err != nil { return fmt.Errorf("could not update quote request status: %w", err) } - //tmpdebug - fmt.Println("handleCommitConfirmed>UpdateRelayNonce: ", request.OriginTxHash) err = q.db.UpdateRelayNonce(ctx, request.TransactionID, nonce) if err != nil { return fmt.Errorf("could not update relay nonce: %w", err) @@ -420,7 +413,7 @@ func (r *Relayer) handleRelayLog(parentCtx context.Context, req *fastbridgev2.Fa reqID, err := r.db.GetQuoteRequestByID(ctx, req.TransactionId) if err != nil { - return fmt.Errorf("could not get quote request: %w", err) + return fmt.Errorf("could not get quote request for tx ID %s: %w", hexutil.Encode(req.TransactionId[:]), err) } // we might've accidentally gotten this later, if so we'll just ignore it // note that in the edge case where we pessimistically marked as DeadlineExceeded @@ -481,13 +474,11 @@ func (q *QuoteRequestHandler) handleRelayCompleted(ctx context.Context, span tra // relay has been finalized, it's time to go back to the origin chain and try to prove _, err = q.Origin.SubmitTransaction(ctx, func(transactor *bind.TransactOpts) (tx *types.Transaction, err error) { - fmt.Println("SubmitTransaction>Prove ", request.OriginTxHash, "Nonce:", transactor.Nonce) tx, err = q.Origin.Bridge.Prove(transactor, request.RawRequest, request.DestTxHash) if err != nil { return nil, fmt.Errorf("could not prove: %w", err) } - fmt.Println("SubmitTransaction>Prove return tx.gas ", tx.Gas()) return tx, nil }) if err != nil {