mirror of
https://github.com/status-im/status-go.git
synced 2025-01-10 06:36:32 +00:00
feat(wallet)!: allowing client to set custom values for fees, nonce, gas
Removed properties from `Path` type: - `MaxFeesPerGas`, based on the sending flow progress appropriate new properties (`TxMaxFeesPerGas`, `ApprovalMaxFeesPerGas`) should be used Added new properties to `Path` type: - `RouterInputParamsUuid`, used to identify from which router input params this path was created - `TxNonce`, used to set nonce for the tx - `TxMaxFeesPerGas`, used to set max fees per gas for the tx - `TxEstimatedTime`, used to estimate time for executing the tx - `ApprovalTxNonce`, used to set nonce for the approval tx - `ApprovalTxMaxFeesPerGas`, used to set max fees per gas for the approval tx - `ApprovalTxEstimatedTime`, used to estimate time for executing the approval tx New request types added: - `PathTxCustomParams`, used to pass tx custom params from the client - `PathTxIdentity`, used to uniquely identify path (tx) to which the custom params need to be applied New endpoints added: - `SetFeeMode` used to set fee mode (`GasFeeLow`, `GasFeeMedium` or `GasFeeHigh`) - `SetCustomTxDetails` used to set custom fee mode (`SetCustomTxDetails`), if this mode is set, client needs to provide: - Max fees per gas - Max priority fee - Nonce - Gas amount
This commit is contained in:
parent
4106224acb
commit
b91c5fd29c
@ -97,7 +97,11 @@ func (c *SendTransactionCommand) Execute(ctx context.Context, request RPCRequest
|
||||
if !fetchedFees.EIP1559Enabled {
|
||||
params.GasPrice = (*hexutil.Big)(fetchedFees.GasPrice)
|
||||
} else {
|
||||
params.MaxFeePerGas = (*hexutil.Big)(fetchedFees.FeeFor(fees.GasFeeMedium))
|
||||
maxFees, err := fetchedFees.FeeFor(fees.GasFeeMedium)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
params.MaxFeePerGas = (*hexutil.Big)(maxFees)
|
||||
params.MaxPriorityFeePerGas = (*hexutil.Big)(fetchedFees.MaxPriorityFeePerGas)
|
||||
}
|
||||
}
|
||||
|
@ -486,6 +486,21 @@ func (api *API) StopSuggestedRoutesCalculation(ctx context.Context) {
|
||||
api.s.router.StopSuggestedRoutesCalculation()
|
||||
}
|
||||
|
||||
// SetFeeMode sets the fee mode for the provided path it should be used for setting predefined fee modes `GasFeeLow`, `GasFeeMedium` and `GasFeeHigh`
|
||||
// in case of setting custom fee use `SetCustomTxDetails` function
|
||||
func (api *API) SetFeeMode(ctx context.Context, pathTxIdentity *requests.PathTxIdentity, feeMode fees.GasFeeMode) error {
|
||||
logutils.ZapLogger().Debug("call to SetFeeMode")
|
||||
|
||||
return api.s.router.SetFeeMode(ctx, pathTxIdentity, feeMode)
|
||||
}
|
||||
|
||||
// SetCustomTxDetails sets custom tx details for the provided path, in case of setting predefined fee modes use `SetFeeMode` function
|
||||
func (api *API) SetCustomTxDetails(ctx context.Context, pathTxIdentity *requests.PathTxIdentity, pathTxCustomParams *requests.PathTxCustomParams) error {
|
||||
logutils.ZapLogger().Debug("call to SetCustomTxDetails")
|
||||
|
||||
return api.s.router.SetCustomTxDetails(ctx, pathTxIdentity, pathTxCustomParams)
|
||||
}
|
||||
|
||||
// Generates addresses for the provided paths, response doesn't include `HasActivity` value (if you need it check `GetAddressDetails` function)
|
||||
func (api *API) GetDerivedAddresses(ctx context.Context, password string, derivedFrom string, paths []string) ([]*DerivedAddress, error) {
|
||||
info, err := api.s.gethManager.AccountsGenerator().LoadAccount(derivedFrom, password)
|
||||
|
@ -55,6 +55,9 @@ type RouteInputParams struct {
|
||||
PublicKey string `json:"publicKey"`
|
||||
PackID *hexutil.Big `json:"packID"`
|
||||
|
||||
// Used internally
|
||||
PathTxCustomParams map[string]*PathTxCustomParams `json:"-"`
|
||||
|
||||
// TODO: Remove two fields below once we implement a better solution for tests
|
||||
// Currently used for tests only
|
||||
TestsMode bool
|
||||
|
50
services/wallet/requests/tx_custom_params.go
Normal file
50
services/wallet/requests/tx_custom_params.go
Normal file
@ -0,0 +1,50 @@
|
||||
package requests
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/status-im/status-go/errors"
|
||||
"github.com/status-im/status-go/services/wallet/router/fees"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrMaxFeesPerGasRequired = &errors.ErrorResponse{Code: errors.ErrorCode("WRC-001"), Details: "maxFeesPerGas is required"}
|
||||
ErrPriorityFeeRequired = &errors.ErrorResponse{Code: errors.ErrorCode("WRC-002"), Details: "priorityFee is required"}
|
||||
)
|
||||
|
||||
type PathTxCustomParams struct {
|
||||
GasFeeMode fees.GasFeeMode `json:"gasFeeMode" validate:"required"`
|
||||
Nonce uint64 `json:"nonce"`
|
||||
GasAmount uint64 `json:"gasAmount"`
|
||||
MaxFeesPerGas *hexutil.Big `json:"maxFeesPerGas"`
|
||||
PriorityFee *hexutil.Big `json:"priorityFee"`
|
||||
}
|
||||
|
||||
type PathTxIdentity struct {
|
||||
RouterInputParamsUuid string `json:"routerInputParamsUuid" validate:"required"`
|
||||
PathName string `json:"pathName" validate:"required"`
|
||||
ChainID uint64 `json:"chainID" validate:"required"`
|
||||
IsApprovalTx bool `json:"isApprovalTx"`
|
||||
}
|
||||
|
||||
func (p *PathTxIdentity) PathIdentity() string {
|
||||
return fmt.Sprintf("%s-%s-%d", p.RouterInputParamsUuid, p.PathName, p.ChainID)
|
||||
}
|
||||
|
||||
func (p *PathTxIdentity) TxIdentityKey() string {
|
||||
return fmt.Sprintf("%s-%v", p.PathIdentity(), p.IsApprovalTx)
|
||||
}
|
||||
|
||||
func (p *PathTxCustomParams) Validate() error {
|
||||
if p.GasFeeMode != fees.GasFeeCustom {
|
||||
return nil
|
||||
}
|
||||
if p.MaxFeesPerGas == nil {
|
||||
return ErrMaxFeesPerGasRequired
|
||||
}
|
||||
if p.PriorityFee == nil {
|
||||
return ErrPriorityFeeRequired
|
||||
}
|
||||
return nil
|
||||
}
|
@ -14,4 +14,10 @@ var (
|
||||
ErrCannotCheckBalance = &errors.ErrorResponse{Code: errors.ErrorCode("WR-006"), Details: "cannot check balance"}
|
||||
ErrLowAmountInForHopBridge = &errors.ErrorResponse{Code: errors.ErrorCode("WR-007"), Details: "bonder fee greater than estimated received, a higher amount is needed to cover fees"}
|
||||
ErrNoPositiveBalance = &errors.ErrorResponse{Code: errors.ErrorCode("WR-008"), Details: "no positive balance"}
|
||||
ErrCustomFeeModeCannotBeSetThisWay = &errors.ErrorResponse{Code: errors.ErrorCode("WR-009"), Details: "custom fee mode cannot be set this way"}
|
||||
ErrOnlyCustomFeeModeCanBeSetThisWay = &errors.ErrorResponse{Code: errors.ErrorCode("WR-010"), Details: "only custom fee mode can be set this way"}
|
||||
ErrTxIdentityNotProvided = &errors.ErrorResponse{Code: errors.ErrorCode("WR-011"), Details: "transaction identity not provided"}
|
||||
ErrTxCustomParamsNotProvided = &errors.ErrorResponse{Code: errors.ErrorCode("WR-012"), Details: "transaction custom params not provided"}
|
||||
ErrCannotCustomizeIfNoRoute = &errors.ErrorResponse{Code: errors.ErrorCode("WR-013"), Details: "cannot customize params if no route"}
|
||||
ErrCannotFindPathForProvidedIdentity = &errors.ErrorResponse{Code: errors.ErrorCode("WR-014"), Details: "cannot find path for provided identity"}
|
||||
)
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/consensus/misc"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
gaspriceoracle "github.com/status-im/status-go/contracts/gas-price-oracle"
|
||||
"github.com/status-im/status-go/errors"
|
||||
"github.com/status-im/status-go/rpc"
|
||||
"github.com/status-im/status-go/rpc/chain"
|
||||
"github.com/status-im/status-go/services/wallet/common"
|
||||
@ -23,6 +24,11 @@ const (
|
||||
GasFeeLow GasFeeMode = iota
|
||||
GasFeeMedium
|
||||
GasFeeHigh
|
||||
GasFeeCustom
|
||||
)
|
||||
|
||||
var (
|
||||
ErrCustomFeeModeNotAvailableInSuggestedFees = &errors.ErrorResponse{Code: errors.ErrorCode("WRF-001"), Details: "custom fee mode is not available in suggested fees"}
|
||||
)
|
||||
|
||||
type MaxFeesLevels struct {
|
||||
@ -50,23 +56,28 @@ type SuggestedFeesGwei struct {
|
||||
MaxFeePerGasLow *big.Float `json:"maxFeePerGasLow"`
|
||||
MaxFeePerGasMedium *big.Float `json:"maxFeePerGasMedium"`
|
||||
MaxFeePerGasHigh *big.Float `json:"maxFeePerGasHigh"`
|
||||
MaxFeePerGasCustom *big.Float `json:"maxFeePerGasCustom"`
|
||||
L1GasFee *big.Float `json:"l1GasFee,omitempty"`
|
||||
EIP1559Enabled bool `json:"eip1559Enabled"`
|
||||
}
|
||||
|
||||
func (m *MaxFeesLevels) FeeFor(mode GasFeeMode) *big.Int {
|
||||
func (m *MaxFeesLevels) FeeFor(mode GasFeeMode) (*big.Int, error) {
|
||||
if mode == GasFeeCustom {
|
||||
return nil, ErrCustomFeeModeNotAvailableInSuggestedFees
|
||||
}
|
||||
|
||||
if mode == GasFeeLow {
|
||||
return m.Low.ToInt()
|
||||
return m.Low.ToInt(), nil
|
||||
}
|
||||
|
||||
if mode == GasFeeHigh {
|
||||
return m.High.ToInt()
|
||||
return m.High.ToInt(), nil
|
||||
}
|
||||
|
||||
return m.Medium.ToInt()
|
||||
return m.Medium.ToInt(), nil
|
||||
}
|
||||
|
||||
func (s *SuggestedFees) FeeFor(mode GasFeeMode) *big.Int {
|
||||
func (s *SuggestedFees) FeeFor(mode GasFeeMode) (*big.Int, error) {
|
||||
return s.MaxFeesLevels.FeeFor(mode)
|
||||
}
|
||||
|
||||
|
@ -296,7 +296,7 @@ func (h *HopBridgeProcessor) sendOrBuild(sendArgs *MultipathProcessorTxArgs, sig
|
||||
|
||||
var nonce uint64
|
||||
if lastUsedNonce < 0 {
|
||||
nonce, err = h.transactor.NextNonce(h.contractMaker.RPCClient, fromChain.ChainID, sendArgs.HopTx.From)
|
||||
nonce, err = h.transactor.NextNonce(context.Background(), h.contractMaker.RPCClient, fromChain.ChainID, sendArgs.HopTx.From)
|
||||
if err != nil {
|
||||
return tx, createBridgeHopErrorResponse(err)
|
||||
}
|
||||
@ -363,7 +363,7 @@ func (h *HopBridgeProcessor) sendOrBuildV2(sendArgs *wallettypes.SendTxArgs, sig
|
||||
|
||||
var nonce uint64
|
||||
if lastUsedNonce < 0 {
|
||||
nonce, err = h.transactor.NextNonce(h.contractMaker.RPCClient, fromChain.ChainID, sendArgs.From)
|
||||
nonce, err = h.transactor.NextNonce(context.Background(), h.contractMaker.RPCClient, fromChain.ChainID, sendArgs.From)
|
||||
if err != nil {
|
||||
return tx, createBridgeHopErrorResponse(err)
|
||||
}
|
||||
|
@ -125,7 +125,7 @@ func (s *ERC1155Processor) sendOrBuild(sendArgs *MultipathProcessorTxArgs, signe
|
||||
|
||||
var nonce uint64
|
||||
if lastUsedNonce < 0 {
|
||||
nonce, err = s.transactor.NextNonce(s.rpcClient, sendArgs.ChainID, sendArgs.ERC1155TransferTx.From)
|
||||
nonce, err = s.transactor.NextNonce(context.Background(), s.rpcClient, sendArgs.ChainID, sendArgs.ERC1155TransferTx.From)
|
||||
if err != nil {
|
||||
return tx, createERC1155ErrorResponse(err)
|
||||
}
|
||||
|
@ -182,7 +182,7 @@ func (s *ERC721Processor) sendOrBuild(sendArgs *MultipathProcessorTxArgs, signer
|
||||
|
||||
var nonce uint64
|
||||
if lastUsedNonce < 0 {
|
||||
nonce, err = s.transactor.NextNonce(s.rpcClient, sendArgs.ChainID, sendArgs.ERC721TransferTx.From)
|
||||
nonce, err = s.transactor.NextNonce(context.Background(), s.rpcClient, sendArgs.ChainID, sendArgs.ERC721TransferTx.From)
|
||||
if err != nil {
|
||||
return tx, createERC721ErrorResponse(err)
|
||||
}
|
||||
|
@ -64,6 +64,7 @@ type SuggestedRoutes struct {
|
||||
|
||||
type Router struct {
|
||||
rpcClient *rpc.Client
|
||||
transactor *transactions.Transactor
|
||||
tokenManager *token.Manager
|
||||
marketManager *market.Manager
|
||||
collectiblesService *collectibles.Service
|
||||
@ -92,6 +93,7 @@ func NewRouter(rpcClient *rpc.Client, transactor *transactions.Transactor, token
|
||||
|
||||
return &Router{
|
||||
rpcClient: rpcClient,
|
||||
transactor: transactor,
|
||||
tokenManager: tokenManager,
|
||||
marketManager: marketManager,
|
||||
collectiblesService: collectibles,
|
||||
@ -140,6 +142,57 @@ func (r *Router) SetTestBalanceMap(balanceMap map[string]*big.Int) {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Router) setCustomTxDetails(pathTxIdentity *requests.PathTxIdentity, pathTxCustomParams *requests.PathTxCustomParams) error {
|
||||
if pathTxIdentity == nil {
|
||||
return ErrTxIdentityNotProvided
|
||||
}
|
||||
if pathTxCustomParams == nil {
|
||||
return ErrTxCustomParamsNotProvided
|
||||
}
|
||||
err := pathTxCustomParams.Validate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r.activeRoutesMutex.Lock()
|
||||
defer r.activeRoutesMutex.Unlock()
|
||||
if r.activeRoutes == nil || len(r.activeRoutes.Best) == 0 {
|
||||
return ErrCannotCustomizeIfNoRoute
|
||||
}
|
||||
|
||||
for _, path := range r.activeRoutes.Best {
|
||||
if path.PathIdentity() != pathTxIdentity.PathIdentity() {
|
||||
continue
|
||||
}
|
||||
|
||||
r.lastInputParamsMutex.Lock()
|
||||
if r.lastInputParams.PathTxCustomParams == nil {
|
||||
r.lastInputParams.PathTxCustomParams = make(map[string]*requests.PathTxCustomParams)
|
||||
}
|
||||
r.lastInputParams.PathTxCustomParams[pathTxIdentity.TxIdentityKey()] = pathTxCustomParams
|
||||
r.lastInputParamsMutex.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return ErrCannotFindPathForProvidedIdentity
|
||||
}
|
||||
|
||||
func (r *Router) SetFeeMode(ctx context.Context, pathTxIdentity *requests.PathTxIdentity, feeMode fees.GasFeeMode) error {
|
||||
if feeMode == fees.GasFeeCustom {
|
||||
return ErrCustomFeeModeCannotBeSetThisWay
|
||||
}
|
||||
|
||||
return r.setCustomTxDetails(pathTxIdentity, &requests.PathTxCustomParams{GasFeeMode: feeMode})
|
||||
}
|
||||
|
||||
func (r *Router) SetCustomTxDetails(ctx context.Context, pathTxIdentity *requests.PathTxIdentity, pathTxCustomParams *requests.PathTxCustomParams) error {
|
||||
if pathTxCustomParams != nil && pathTxCustomParams.GasFeeMode != fees.GasFeeCustom {
|
||||
return ErrOnlyCustomFeeModeCanBeSetThisWay
|
||||
}
|
||||
return r.setCustomTxDetails(pathTxIdentity, pathTxCustomParams)
|
||||
}
|
||||
|
||||
func newSuggestedRoutes(
|
||||
input *requests.RouteInputParams,
|
||||
candidates routes.Route,
|
||||
@ -585,7 +638,11 @@ func (r *Router) resolveCandidates(ctx context.Context, input *requests.RouteInp
|
||||
var (
|
||||
testsMode = input.TestsMode && input.TestParams != nil
|
||||
group = async.NewAtomicGroup(ctx)
|
||||
mu sync.Mutex
|
||||
|
||||
candidatesMu sync.Mutex
|
||||
|
||||
usedNonces = make(map[uint64]uint64)
|
||||
usedNoncesMu sync.Mutex
|
||||
)
|
||||
|
||||
crossChainAmountOptions, err := r.findOptionsForSendingAmount(input, selectedFromChains)
|
||||
@ -601,8 +658,8 @@ func (r *Router) resolveCandidates(ctx context.Context, input *requests.RouteInp
|
||||
zap.Uint64("toChainId", toChainID),
|
||||
zap.Stringer("amount", amount),
|
||||
zap.Error(err))
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
candidatesMu.Lock()
|
||||
defer candidatesMu.Unlock()
|
||||
processorErrors = append(processorErrors, &ProcessorError{
|
||||
ProcessorName: processorName,
|
||||
Error: err,
|
||||
@ -610,8 +667,8 @@ func (r *Router) resolveCandidates(ctx context.Context, input *requests.RouteInp
|
||||
}
|
||||
|
||||
appendPathFn := func(path *routes.Path) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
candidatesMu.Lock()
|
||||
defer candidatesMu.Unlock()
|
||||
candidates = append(candidates, path)
|
||||
}
|
||||
|
||||
@ -765,14 +822,8 @@ func (r *Router) resolveCandidates(ctx context.Context, input *requests.RouteInp
|
||||
continue
|
||||
}
|
||||
|
||||
maxFeesPerGas := fetchedFees.FeeFor(input.GasFeeMode)
|
||||
|
||||
estimatedTime := r.feesManager.TransactionEstimatedTime(ctx, network.ChainID, maxFeesPerGas)
|
||||
if approvalRequired && estimatedTime < fees.MoreThanFiveMinutes {
|
||||
estimatedTime += 1
|
||||
}
|
||||
|
||||
path := &routes.Path{
|
||||
RouterInputParamsUuid: input.Uuid,
|
||||
ProcessorName: pProcessor.Name(),
|
||||
FromChain: network,
|
||||
ToChain: dest,
|
||||
@ -792,12 +843,12 @@ func (r *Router) resolveCandidates(ctx context.Context, input *requests.RouteInp
|
||||
ApprovalContractAddress: &approvalContractAddress,
|
||||
ApprovalGasAmount: approvalGasLimit,
|
||||
|
||||
EstimatedTime: estimatedTime,
|
||||
|
||||
SubtractFees: amountOption.subtractFees,
|
||||
}
|
||||
|
||||
err = r.cacluateFees(ctx, path, fetchedFees, processorInputParams.TestsMode, processorInputParams.TestApprovalL1Fee)
|
||||
usedNoncesMu.Lock()
|
||||
err = r.evaluateAndUpdatePathDetails(ctx, path, fetchedFees, usedNonces, processorInputParams.TestsMode, processorInputParams.TestApprovalL1Fee)
|
||||
usedNoncesMu.Unlock()
|
||||
if err != nil {
|
||||
appendProcessorErrorFn(pProcessor.Name(), input.SendType, processorInputParams.FromChain.ChainID, processorInputParams.ToChain.ChainID, processorInputParams.AmountIn, err)
|
||||
continue
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/status-im/status-go/contracts"
|
||||
gaspriceoracle "github.com/status-im/status-go/contracts/gas-price-oracle"
|
||||
"github.com/status-im/status-go/eth-node/types"
|
||||
"github.com/status-im/status-go/params"
|
||||
"github.com/status-im/status-go/rpc/chain"
|
||||
"github.com/status-im/status-go/services/wallet/bigint"
|
||||
@ -21,7 +22,7 @@ import (
|
||||
"github.com/status-im/status-go/services/wallet/market"
|
||||
"github.com/status-im/status-go/services/wallet/router/fees"
|
||||
"github.com/status-im/status-go/services/wallet/router/pathprocessor"
|
||||
routs "github.com/status-im/status-go/services/wallet/router/routes"
|
||||
"github.com/status-im/status-go/services/wallet/router/routes"
|
||||
"github.com/status-im/status-go/services/wallet/router/sendtype"
|
||||
"github.com/status-im/status-go/services/wallet/token"
|
||||
)
|
||||
@ -156,11 +157,110 @@ func (r *Router) getBalance(ctx context.Context, chainID uint64, token *token.To
|
||||
return r.tokenManager.GetBalance(ctx, client, account, token.Address)
|
||||
}
|
||||
|
||||
func (r *Router) cacluateFees(ctx context.Context, path *routs.Path, fetchedFees *fees.SuggestedFees, testsMode bool, testApprovalL1Fee uint64) (err error) {
|
||||
func (r *Router) resolveNonceForPath(ctx context.Context, path *routes.Path, address common.Address, usedNonces map[uint64]uint64) error {
|
||||
var nextNonce uint64
|
||||
if nonce, ok := usedNonces[path.FromChain.ChainID]; ok {
|
||||
nextNonce = nonce + 1
|
||||
} else {
|
||||
nonce, err := r.transactor.NextNonce(ctx, r.rpcClient, path.FromChain.ChainID, types.Address(address))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nextNonce = nonce
|
||||
}
|
||||
|
||||
usedNonces[path.FromChain.ChainID] = nextNonce
|
||||
if !path.ApprovalRequired {
|
||||
path.TxNonce = (*hexutil.Uint64)(&nextNonce)
|
||||
} else {
|
||||
path.ApprovalTxNonce = (*hexutil.Uint64)(&nextNonce)
|
||||
txNonce := nextNonce + 1
|
||||
path.TxNonce = (*hexutil.Uint64)(&txNonce)
|
||||
|
||||
usedNonces[path.FromChain.ChainID] = txNonce
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Router) applyCustomFields(ctx context.Context, path *routes.Path, fetchedFees *fees.SuggestedFees, usedNonces map[uint64]uint64) error {
|
||||
r.lastInputParamsMutex.Lock()
|
||||
defer r.lastInputParamsMutex.Unlock()
|
||||
|
||||
// set appropriate nonce/s, and update later in this function if custom nonce/s are provided
|
||||
err := r.resolveNonceForPath(ctx, path, r.lastInputParams.AddrFrom, usedNonces)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if r.lastInputParams.PathTxCustomParams == nil || len(r.lastInputParams.PathTxCustomParams) == 0 {
|
||||
// if no custom params are provided, use the initial fee mode
|
||||
maxFeesPerGas, err := fetchedFees.FeeFor(r.lastInputParams.GasFeeMode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if path.ApprovalRequired {
|
||||
path.ApprovalMaxFeesPerGas = (*hexutil.Big)(maxFeesPerGas)
|
||||
path.ApprovalBaseFee = (*hexutil.Big)(fetchedFees.BaseFee)
|
||||
path.ApprovalPriorityFee = (*hexutil.Big)(fetchedFees.MaxPriorityFeePerGas)
|
||||
}
|
||||
|
||||
path.TxMaxFeesPerGas = (*hexutil.Big)(maxFeesPerGas)
|
||||
path.TxBaseFee = (*hexutil.Big)(fetchedFees.BaseFee)
|
||||
path.TxPriorityFee = (*hexutil.Big)(fetchedFees.MaxPriorityFeePerGas)
|
||||
} else {
|
||||
if path.ApprovalRequired {
|
||||
approvalTxIdentityKey := path.TxIdentityKey(true)
|
||||
if approvalTxCustomParams, ok := r.lastInputParams.PathTxCustomParams[approvalTxIdentityKey]; ok {
|
||||
if approvalTxCustomParams.GasFeeMode != fees.GasFeeCustom {
|
||||
maxFeesPerGas, err := fetchedFees.FeeFor(approvalTxCustomParams.GasFeeMode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
path.ApprovalMaxFeesPerGas = (*hexutil.Big)(maxFeesPerGas)
|
||||
path.ApprovalBaseFee = (*hexutil.Big)(fetchedFees.BaseFee)
|
||||
path.ApprovalPriorityFee = (*hexutil.Big)(fetchedFees.MaxPriorityFeePerGas)
|
||||
} else {
|
||||
path.ApprovalTxNonce = (*hexutil.Uint64)(&approvalTxCustomParams.Nonce)
|
||||
path.ApprovalGasAmount = approvalTxCustomParams.GasAmount
|
||||
path.ApprovalMaxFeesPerGas = approvalTxCustomParams.MaxFeesPerGas
|
||||
path.ApprovalBaseFee = (*hexutil.Big)(new(big.Int).Sub(approvalTxCustomParams.MaxFeesPerGas.ToInt(), approvalTxCustomParams.PriorityFee.ToInt()))
|
||||
path.ApprovalPriorityFee = approvalTxCustomParams.PriorityFee
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
txIdentityKey := path.TxIdentityKey(false)
|
||||
if txCustomParams, ok := r.lastInputParams.PathTxCustomParams[txIdentityKey]; ok {
|
||||
if txCustomParams.GasFeeMode != fees.GasFeeCustom {
|
||||
maxFeesPerGas, err := fetchedFees.FeeFor(txCustomParams.GasFeeMode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
path.TxMaxFeesPerGas = (*hexutil.Big)(maxFeesPerGas)
|
||||
path.TxBaseFee = (*hexutil.Big)(fetchedFees.BaseFee)
|
||||
path.TxPriorityFee = (*hexutil.Big)(fetchedFees.MaxPriorityFeePerGas)
|
||||
} else {
|
||||
path.TxNonce = (*hexutil.Uint64)(&txCustomParams.Nonce)
|
||||
path.TxGasAmount = txCustomParams.GasAmount
|
||||
path.TxMaxFeesPerGas = txCustomParams.MaxFeesPerGas
|
||||
path.TxBaseFee = (*hexutil.Big)(new(big.Int).Sub(txCustomParams.MaxFeesPerGas.ToInt(), txCustomParams.PriorityFee.ToInt()))
|
||||
path.TxPriorityFee = txCustomParams.PriorityFee
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Router) evaluateAndUpdatePathDetails(ctx context.Context, path *routes.Path, fetchedFees *fees.SuggestedFees,
|
||||
usedNonces map[uint64]uint64, testsMode bool, testApprovalL1Fee uint64) (err error) {
|
||||
|
||||
var (
|
||||
l1ApprovalFee uint64
|
||||
)
|
||||
if testsMode {
|
||||
usedNonces[path.FromChain.ChainID] = usedNonces[path.FromChain.ChainID] + 1
|
||||
}
|
||||
if path.ApprovalRequired {
|
||||
if testsMode {
|
||||
l1ApprovalFee = testApprovalL1Fee
|
||||
@ -172,6 +272,11 @@ func (r *Router) cacluateFees(ctx context.Context, path *routs.Path, fetchedFees
|
||||
}
|
||||
}
|
||||
|
||||
err = r.applyCustomFields(ctx, path, fetchedFees, usedNonces)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: keep l1 fees at 0 until we have the correct algorithm, as we do base fee x 2 that should cover the l1 fees
|
||||
var l1FeeWei uint64 = 0
|
||||
// if input.SendType.needL1Fee() {
|
||||
@ -183,14 +288,9 @@ func (r *Router) cacluateFees(ctx context.Context, path *routs.Path, fetchedFees
|
||||
// l1FeeWei, _ = r.feesManager.GetL1Fee(ctx, network.ChainID, txInputData)
|
||||
// }
|
||||
|
||||
r.lastInputParamsMutex.Lock()
|
||||
gasFeeMode := r.lastInputParams.GasFeeMode
|
||||
r.lastInputParamsMutex.Unlock()
|
||||
maxFeesPerGas := fetchedFees.FeeFor(gasFeeMode)
|
||||
|
||||
// calculate ETH fees
|
||||
ethTotalFees := big.NewInt(0)
|
||||
txFeeInWei := new(big.Int).Mul(maxFeesPerGas, big.NewInt(int64(path.TxGasAmount)))
|
||||
txFeeInWei := new(big.Int).Mul(path.TxMaxFeesPerGas.ToInt(), big.NewInt(int64(path.TxGasAmount)))
|
||||
ethTotalFees.Add(ethTotalFees, txFeeInWei)
|
||||
|
||||
txL1FeeInWei := big.NewInt(0)
|
||||
@ -202,7 +302,7 @@ func (r *Router) cacluateFees(ctx context.Context, path *routs.Path, fetchedFees
|
||||
approvalFeeInWei := big.NewInt(0)
|
||||
approvalL1FeeInWei := big.NewInt(0)
|
||||
if path.ApprovalRequired {
|
||||
approvalFeeInWei.Mul(maxFeesPerGas, big.NewInt(int64(path.ApprovalGasAmount)))
|
||||
approvalFeeInWei.Mul(path.ApprovalMaxFeesPerGas.ToInt(), big.NewInt(int64(path.ApprovalGasAmount)))
|
||||
ethTotalFees.Add(ethTotalFees, approvalFeeInWei)
|
||||
|
||||
if l1ApprovalFee > 0 {
|
||||
@ -227,17 +327,10 @@ func (r *Router) cacluateFees(ctx context.Context, path *routs.Path, fetchedFees
|
||||
|
||||
// set the values
|
||||
path.SuggestedLevelsForMaxFeesPerGas = fetchedFees.MaxFeesLevels
|
||||
path.MaxFeesPerGas = (*hexutil.Big)(maxFeesPerGas)
|
||||
|
||||
path.TxBaseFee = (*hexutil.Big)(fetchedFees.BaseFee)
|
||||
path.TxPriorityFee = (*hexutil.Big)(fetchedFees.MaxPriorityFeePerGas)
|
||||
|
||||
path.TxFee = (*hexutil.Big)(txFeeInWei)
|
||||
path.TxL1Fee = (*hexutil.Big)(txL1FeeInWei)
|
||||
|
||||
path.ApprovalBaseFee = (*hexutil.Big)(fetchedFees.BaseFee)
|
||||
path.ApprovalPriorityFee = (*hexutil.Big)(fetchedFees.MaxPriorityFeePerGas)
|
||||
|
||||
path.ApprovalFee = (*hexutil.Big)(approvalFeeInWei)
|
||||
path.ApprovalL1Fee = (*hexutil.Big)(approvalL1FeeInWei)
|
||||
|
||||
@ -246,7 +339,12 @@ func (r *Router) cacluateFees(ctx context.Context, path *routs.Path, fetchedFees
|
||||
path.RequiredTokenBalance = requiredTokenBalance
|
||||
path.RequiredNativeBalance = requiredNativeBalance
|
||||
|
||||
return nil
|
||||
path.TxEstimatedTime = r.feesManager.TransactionEstimatedTime(ctx, path.FromChain.ChainID, path.TxMaxFeesPerGas.ToInt())
|
||||
if path.ApprovalRequired {
|
||||
path.ApprovalEstimatedTime = r.feesManager.TransactionEstimatedTime(ctx, path.FromChain.ChainID, path.ApprovalMaxFeesPerGas.ToInt())
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func findToken(sendType sendtype.SendType, tokenManager *token.Manager, collectibles *collectibles.Service, account common.Address, network *params.Network, tokenID string) *token.Token {
|
||||
|
@ -78,18 +78,21 @@ func (r *Router) subscribeForUdates(chainID uint64) error {
|
||||
blockNumber, err := ethClient.BlockNumber(ctx)
|
||||
if err != nil {
|
||||
logutils.ZapLogger().Error("Failed to get block number", zap.Error(err))
|
||||
r.sendUpdatesError(err)
|
||||
continue
|
||||
}
|
||||
|
||||
val, ok := r.clientsForUpdatesPerChains.Load(chainID)
|
||||
if !ok {
|
||||
logutils.ZapLogger().Error("Failed to get fetchingLastBlock", zap.Uint64("chain", chainID))
|
||||
logutils.ZapLogger().Error("Failed to get last block details", zap.Uint64("chain", chainID))
|
||||
r.sendUpdatesError(err)
|
||||
continue
|
||||
}
|
||||
|
||||
flbLoaded, ok := val.(fetchingLastBlock)
|
||||
if !ok {
|
||||
logutils.ZapLogger().Error("Failed to get fetchingLastBlock", zap.Uint64("chain", chainID))
|
||||
logutils.ZapLogger().Error("Failed to cast last block details", zap.Uint64("chain", chainID))
|
||||
r.sendUpdatesError(err)
|
||||
continue
|
||||
}
|
||||
|
||||
@ -100,28 +103,37 @@ func (r *Router) subscribeForUdates(chainID uint64) error {
|
||||
fees, err := r.feesManager.SuggestedFees(ctx, chainID)
|
||||
if err != nil {
|
||||
logutils.ZapLogger().Error("Failed to get suggested fees", zap.Error(err))
|
||||
r.sendUpdatesError(err)
|
||||
continue
|
||||
}
|
||||
|
||||
r.lastInputParamsMutex.Lock()
|
||||
uuid := r.lastInputParams.Uuid
|
||||
r.lastInputParamsMutex.Unlock()
|
||||
|
||||
r.activeRoutesMutex.Lock()
|
||||
if r.activeRoutes != nil && r.activeRoutes.Best != nil && len(r.activeRoutes.Best) > 0 {
|
||||
usedNonces := make(map[uint64]uint64)
|
||||
for _, path := range r.activeRoutes.Best {
|
||||
err = r.cacluateFees(ctx, path, fees, false, 0)
|
||||
err = r.evaluateAndUpdatePathDetails(ctx, path, fees, usedNonces, false, 0)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
logutils.ZapLogger().Error("Failed to calculate fees", zap.Error(err))
|
||||
r.activeRoutesMutex.Unlock()
|
||||
r.sendUpdatesError(err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
_, err = r.checkBalancesForTheBestRoute(ctx, r.activeRoutes.Best)
|
||||
|
||||
sendRouterResult(uuid, r.activeRoutes, err)
|
||||
if err != nil {
|
||||
logutils.ZapLogger().Error("Failed to check balances for the best route", zap.Error(err))
|
||||
r.activeRoutesMutex.Unlock()
|
||||
r.sendUpdatesError(err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
r.activeRoutesMutex.Unlock()
|
||||
|
||||
r.sendUpdatesError(err)
|
||||
}
|
||||
case <-flb.closeCh:
|
||||
ticker.Stop()
|
||||
@ -133,6 +145,17 @@ func (r *Router) subscribeForUdates(chainID uint64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Router) sendUpdatesError(err error) {
|
||||
r.lastInputParamsMutex.Lock()
|
||||
uuid := r.lastInputParams.Uuid
|
||||
r.lastInputParamsMutex.Unlock()
|
||||
|
||||
r.activeRoutesMutex.Lock()
|
||||
defer r.activeRoutesMutex.Unlock()
|
||||
|
||||
sendRouterResult(uuid, r.activeRoutes, err)
|
||||
}
|
||||
|
||||
func (r *Router) startTimeoutForUpdates(closeCh chan struct{}, timeout time.Duration) {
|
||||
dedlineTicker := time.NewTicker(timeout)
|
||||
go func() {
|
||||
|
@ -1,8 +1,8 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strconv"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
@ -12,6 +12,7 @@ import (
|
||||
)
|
||||
|
||||
type Path struct {
|
||||
RouterInputParamsUuid string
|
||||
ProcessorName string
|
||||
FromChain *params.Network // Source chain
|
||||
ToChain *params.Network // Destination chain
|
||||
@ -22,13 +23,15 @@ type Path struct {
|
||||
AmountOut *hexutil.Big // Amount that will be received on the destination chain
|
||||
|
||||
SuggestedLevelsForMaxFeesPerGas *fees.MaxFeesLevels // Suggested max fees for the transaction (in ETH WEI)
|
||||
MaxFeesPerGas *hexutil.Big // Max fees per gas (determined by client via GasFeeMode, in ETH WEI)
|
||||
|
||||
TxNonce *hexutil.Uint64 // Nonce for the transaction
|
||||
TxMaxFeesPerGas *hexutil.Big // Max fees per gas (determined by client via GasFeeMode, in ETH WEI)
|
||||
TxBaseFee *hexutil.Big // Base fee for the transaction (in ETH WEI)
|
||||
TxPriorityFee *hexutil.Big // Priority fee for the transaction (in ETH WEI)
|
||||
TxGasAmount uint64 // Gas used for the transaction
|
||||
TxBonderFees *hexutil.Big // Bonder fees for the transaction - used for Hop bridge (in selected token)
|
||||
TxTokenFees *hexutil.Big // Token fees for the transaction - used for bridges (represent the difference between the amount in and the amount out, in selected token)
|
||||
TxEstimatedTime fees.TransactionEstimation
|
||||
|
||||
TxFee *hexutil.Big // fee for the transaction (includes tx fee only, doesn't include approval fees, l1 fees, l1 approval fees, token fees or bonders fees, in ETH WEI)
|
||||
TxL1Fee *hexutil.Big // L1 fee for the transaction - used for for transactions placed on L2 chains (in ETH WEI)
|
||||
@ -36,34 +39,45 @@ type Path struct {
|
||||
ApprovalRequired bool // Is approval required for the transaction
|
||||
ApprovalAmountRequired *hexutil.Big // Amount required for the approval transaction
|
||||
ApprovalContractAddress *common.Address // Address of the contract that needs to be approved
|
||||
ApprovalTxNonce *hexutil.Uint64 // Nonce for the transaction
|
||||
ApprovalMaxFeesPerGas *hexutil.Big // Max fees per gas (determined by client via GasFeeMode, in ETH WEI)
|
||||
ApprovalBaseFee *hexutil.Big // Base fee for the approval transaction (in ETH WEI)
|
||||
ApprovalPriorityFee *hexutil.Big // Priority fee for the approval transaction (in ETH WEI)
|
||||
ApprovalGasAmount uint64 // Gas used for the approval transaction
|
||||
ApprovalEstimatedTime fees.TransactionEstimation
|
||||
|
||||
ApprovalFee *hexutil.Big // Total fee for the approval transaction (includes approval tx fees only, doesn't include approval l1 fees, in ETH WEI)
|
||||
ApprovalL1Fee *hexutil.Big // L1 fee for the approval transaction - used for for transactions placed on L2 chains (in ETH WEI)
|
||||
|
||||
TxTotalFee *hexutil.Big // Total fee for the transaction (includes tx fees, approval fees, l1 fees, l1 approval fees, in ETH WEI)
|
||||
|
||||
EstimatedTime fees.TransactionEstimation
|
||||
|
||||
RequiredTokenBalance *big.Int // (in selected token)
|
||||
RequiredNativeBalance *big.Int // (in ETH WEI)
|
||||
SubtractFees bool
|
||||
}
|
||||
|
||||
func (p *Path) PathIdentity() string {
|
||||
return fmt.Sprintf("%s-%s-%d", p.RouterInputParamsUuid, p.ProcessorName, p.FromChain.ChainID)
|
||||
}
|
||||
|
||||
func (p *Path) TxIdentityKey(approval bool) string {
|
||||
return fmt.Sprintf("%s-%v", p.PathIdentity(), approval)
|
||||
}
|
||||
|
||||
func (p *Path) Equal(o *Path) bool {
|
||||
return p.FromChain.ChainID == o.FromChain.ChainID && p.ToChain.ChainID == o.ToChain.ChainID
|
||||
}
|
||||
|
||||
func (p *Path) Copy() *Path {
|
||||
newPath := &Path{
|
||||
RouterInputParamsUuid: p.RouterInputParamsUuid,
|
||||
ProcessorName: p.ProcessorName,
|
||||
AmountInLocked: p.AmountInLocked,
|
||||
TxGasAmount: p.TxGasAmount,
|
||||
TxEstimatedTime: p.TxEstimatedTime,
|
||||
ApprovalRequired: p.ApprovalRequired,
|
||||
ApprovalGasAmount: p.ApprovalGasAmount,
|
||||
EstimatedTime: p.EstimatedTime,
|
||||
ApprovalEstimatedTime: p.ApprovalEstimatedTime,
|
||||
SubtractFees: p.SubtractFees,
|
||||
}
|
||||
|
||||
@ -103,8 +117,13 @@ func (p *Path) Copy() *Path {
|
||||
}
|
||||
}
|
||||
|
||||
if p.MaxFeesPerGas != nil {
|
||||
newPath.MaxFeesPerGas = (*hexutil.Big)(big.NewInt(0).Set(p.MaxFeesPerGas.ToInt()))
|
||||
if p.TxNonce != nil {
|
||||
txNonce := *p.TxNonce
|
||||
newPath.TxNonce = &txNonce
|
||||
}
|
||||
|
||||
if p.TxMaxFeesPerGas != nil {
|
||||
newPath.TxMaxFeesPerGas = (*hexutil.Big)(big.NewInt(0).Set(p.TxMaxFeesPerGas.ToInt()))
|
||||
}
|
||||
|
||||
if p.TxBaseFee != nil {
|
||||
@ -140,6 +159,15 @@ func (p *Path) Copy() *Path {
|
||||
newPath.ApprovalContractAddress = &addr
|
||||
}
|
||||
|
||||
if p.ApprovalTxNonce != nil {
|
||||
approvalTxNonce := *p.ApprovalTxNonce
|
||||
newPath.ApprovalTxNonce = &approvalTxNonce
|
||||
}
|
||||
|
||||
if p.ApprovalMaxFeesPerGas != nil {
|
||||
newPath.ApprovalMaxFeesPerGas = (*hexutil.Big)(big.NewInt(0).Set(p.ApprovalMaxFeesPerGas.ToInt()))
|
||||
}
|
||||
|
||||
if p.ApprovalBaseFee != nil {
|
||||
newPath.ApprovalBaseFee = (*hexutil.Big)(big.NewInt(0).Set(p.ApprovalBaseFee.ToInt()))
|
||||
}
|
||||
@ -170,9 +198,3 @@ func (p *Path) Copy() *Path {
|
||||
|
||||
return newPath
|
||||
}
|
||||
|
||||
// ID that uniquely identifies a path in a given route
|
||||
func (p *Path) ID() string {
|
||||
// A route will contain at most a single path from a given processor for a given origin chain
|
||||
return p.ProcessorName + "-" + strconv.Itoa(int(p.FromChain.ChainID))
|
||||
}
|
||||
|
@ -30,24 +30,26 @@ func TestCopyPath(t *testing.T) {
|
||||
Medium: (*hexutil.Big)(big.NewInt(200)),
|
||||
High: (*hexutil.Big)(big.NewInt(300)),
|
||||
},
|
||||
MaxFeesPerGas: (*hexutil.Big)(big.NewInt(100)),
|
||||
TxMaxFeesPerGas: (*hexutil.Big)(big.NewInt(100)),
|
||||
TxBaseFee: (*hexutil.Big)(big.NewInt(100)),
|
||||
TxPriorityFee: (*hexutil.Big)(big.NewInt(100)),
|
||||
TxGasAmount: 100,
|
||||
TxBonderFees: (*hexutil.Big)(big.NewInt(100)),
|
||||
TxTokenFees: (*hexutil.Big)(big.NewInt(100)),
|
||||
TxEstimatedTime: fees.TransactionEstimation(100),
|
||||
TxFee: (*hexutil.Big)(big.NewInt(100)),
|
||||
TxL1Fee: (*hexutil.Big)(big.NewInt(100)),
|
||||
ApprovalRequired: true,
|
||||
ApprovalAmountRequired: (*hexutil.Big)(big.NewInt(100)),
|
||||
ApprovalContractAddress: &addr,
|
||||
ApprovalMaxFeesPerGas: (*hexutil.Big)(big.NewInt(100)),
|
||||
ApprovalBaseFee: (*hexutil.Big)(big.NewInt(100)),
|
||||
ApprovalPriorityFee: (*hexutil.Big)(big.NewInt(100)),
|
||||
ApprovalGasAmount: 100,
|
||||
ApprovalEstimatedTime: fees.TransactionEstimation(100),
|
||||
ApprovalFee: (*hexutil.Big)(big.NewInt(100)),
|
||||
ApprovalL1Fee: (*hexutil.Big)(big.NewInt(100)),
|
||||
TxTotalFee: (*hexutil.Big)(big.NewInt(100)),
|
||||
EstimatedTime: fees.TransactionEstimation(100),
|
||||
RequiredTokenBalance: big.NewInt(100),
|
||||
RequiredNativeBalance: big.NewInt(100),
|
||||
SubtractFees: true,
|
||||
|
@ -65,7 +65,7 @@ func (tm *TransactionManager) TxPlacedForPath(pathProcessorName string) bool {
|
||||
|
||||
func (tm *TransactionManager) getOrInitDetailsForPath(path *routes.Path) *wallettypes.RouterTransactionDetails {
|
||||
for _, desc := range tm.routerTransactions {
|
||||
if desc.RouterPath.ID() == path.ID() {
|
||||
if desc.RouterPath.PathIdentity() == path.PathIdentity() {
|
||||
return desc
|
||||
}
|
||||
}
|
||||
@ -99,8 +99,9 @@ func buildApprovalTxForPath(transactor transactions.TransactorIface, path *route
|
||||
To: &addrTo,
|
||||
Value: (*hexutil.Big)(big.NewInt(0)),
|
||||
Data: data,
|
||||
Nonce: path.ApprovalTxNonce,
|
||||
Gas: (*hexutil.Uint64)(&path.ApprovalGasAmount),
|
||||
MaxFeePerGas: path.MaxFeesPerGas,
|
||||
MaxFeePerGas: path.ApprovalMaxFeesPerGas,
|
||||
MaxPriorityFeePerGas: path.ApprovalPriorityFee,
|
||||
ValueOut: (*hexutil.Big)(big.NewInt(0)),
|
||||
|
||||
@ -125,7 +126,7 @@ func buildApprovalTxForPath(transactor transactions.TransactorIface, path *route
|
||||
}, nil
|
||||
}
|
||||
|
||||
func buildTxForPath(transactor transactions.TransactorIface, path *routes.Path, pathProcessors map[string]pathprocessor.PathProcessor,
|
||||
func buildTxForPath(path *routes.Path, pathProcessors map[string]pathprocessor.PathProcessor,
|
||||
usedNonces map[uint64]int64, signer ethTypes.Signer, params BuildRouteExtraParams) (*wallettypes.TransactionData, error) {
|
||||
lastUsedNonce := int64(-1)
|
||||
if nonce, ok := usedNonces[path.FromChain.ChainID]; ok {
|
||||
@ -161,8 +162,9 @@ func buildTxForPath(transactor transactions.TransactorIface, path *routes.Path,
|
||||
To: &addrTo,
|
||||
Value: path.AmountIn,
|
||||
Data: data,
|
||||
Nonce: path.TxNonce,
|
||||
Gas: (*hexutil.Uint64)(&path.TxGasAmount),
|
||||
MaxFeePerGas: path.MaxFeesPerGas,
|
||||
MaxFeePerGas: path.TxMaxFeesPerGas,
|
||||
MaxPriorityFeePerGas: path.TxPriorityFee,
|
||||
|
||||
// additional fields version 1
|
||||
@ -257,7 +259,7 @@ func (tm *TransactionManager) BuildTransactionsFromRoute(route routes.Route, pat
|
||||
}
|
||||
|
||||
// build tx for the path
|
||||
txDetails.TxData, err = buildTxForPath(tm.transactor, path, pathProcessors, usedNonces, signer, params)
|
||||
txDetails.TxData, err = buildTxForPath(path, pathProcessors, usedNonces, signer, params)
|
||||
if err != nil {
|
||||
return nil, path.FromChain.ChainID, path.ToChain.ChainID, err
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ func (e *ErrBadNonce) Error() string {
|
||||
|
||||
// Transactor is an interface that defines the methods for validating and sending transactions.
|
||||
type TransactorIface interface {
|
||||
NextNonce(rpcClient rpc.ClientInterface, chainID uint64, from types.Address) (uint64, error)
|
||||
NextNonce(ctx context.Context, rpcClient rpc.ClientInterface, chainID uint64, from types.Address) (uint64, error)
|
||||
EstimateGas(network *params.Network, from common.Address, to common.Address, value *big.Int, input []byte) (uint64, error)
|
||||
SendTransaction(sendArgs wallettypes.SendTxArgs, verifiedAccount *account.SelectedExtKey, lastUsedNonce int64) (hash types.Hash, nonce uint64, err error)
|
||||
SendTransactionWithChainID(chainID uint64, sendArgs wallettypes.SendTxArgs, lastUsedNonce int64, verifiedAccount *account.SelectedExtKey) (hash types.Hash, nonce uint64, err error)
|
||||
@ -102,9 +102,8 @@ func (t *Transactor) SetRPC(rpcClient *rpc.Client, timeout time.Duration) {
|
||||
t.rpcCallTimeout = timeout
|
||||
}
|
||||
|
||||
func (t *Transactor) NextNonce(rpcClient rpc.ClientInterface, chainID uint64, from types.Address) (uint64, error) {
|
||||
func (t *Transactor) NextNonce(ctx context.Context, rpcClient rpc.ClientInterface, chainID uint64, from types.Address) (uint64, error) {
|
||||
wrapper := newRPCWrapper(rpcClient, chainID)
|
||||
ctx := context.Background()
|
||||
nonce, err := wrapper.PendingNonceAt(ctx, common.Address(from))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
@ -256,8 +255,11 @@ func (t *Transactor) BuildTransactionWithSignature(chainID uint64, args walletty
|
||||
return nil, ErrInvalidSignatureSize
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), t.rpcCallTimeout)
|
||||
defer cancel()
|
||||
|
||||
tx := t.buildTransaction(args)
|
||||
expectedNonce, err := t.NextNonce(t.rpcWrapper.RPCClient, chainID, args.From)
|
||||
expectedNonce, err := t.NextNonce(ctx, t.rpcWrapper.RPCClient, chainID, args.From)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -281,7 +283,10 @@ func (t *Transactor) HashTransaction(args wallettypes.SendTxArgs) (validatedArgs
|
||||
|
||||
validatedArgs = args
|
||||
|
||||
nonce, err := t.NextNonce(t.rpcWrapper.RPCClient, t.rpcWrapper.chainID, args.From)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), t.rpcCallTimeout)
|
||||
defer cancel()
|
||||
|
||||
nonce, err := t.NextNonce(ctx, t.rpcWrapper.RPCClient, t.rpcWrapper.chainID, args.From)
|
||||
if err != nil {
|
||||
return validatedArgs, hash, err
|
||||
}
|
||||
@ -290,8 +295,6 @@ func (t *Transactor) HashTransaction(args wallettypes.SendTxArgs) (validatedArgs
|
||||
gasFeeCap := (*big.Int)(args.MaxFeePerGas)
|
||||
gasTipCap := (*big.Int)(args.MaxPriorityFeePerGas)
|
||||
if args.GasPrice == nil && !args.IsDynamicFeeTx() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), t.rpcCallTimeout)
|
||||
defer cancel()
|
||||
gasPrice, err = t.rpcWrapper.SuggestGasPrice(ctx)
|
||||
if err != nil {
|
||||
return validatedArgs, hash, err
|
||||
@ -303,9 +306,6 @@ func (t *Transactor) HashTransaction(args wallettypes.SendTxArgs) (validatedArgs
|
||||
|
||||
var gas uint64
|
||||
if args.Gas == nil {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), t.rpcCallTimeout)
|
||||
defer cancel()
|
||||
|
||||
var (
|
||||
gethTo common.Address
|
||||
gethToPtr *common.Address
|
||||
@ -374,13 +374,16 @@ func (t *Transactor) validateAndBuildTransaction(rpcWrapper *rpcWrapper, args wa
|
||||
return tx, wallettypes.ErrInvalidSendTxArgs
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), t.rpcCallTimeout)
|
||||
defer cancel()
|
||||
|
||||
var nonce uint64
|
||||
if args.Nonce != nil {
|
||||
nonce = uint64(*args.Nonce)
|
||||
} else {
|
||||
// some chains, like arbitrum doesn't count pending txs in the nonce, so we need to calculate it manually
|
||||
if lastUsedNonce < 0 {
|
||||
nonce, err = t.NextNonce(rpcWrapper.RPCClient, rpcWrapper.chainID, args.From)
|
||||
nonce, err = t.NextNonce(ctx, rpcWrapper.RPCClient, rpcWrapper.chainID, args.From)
|
||||
if err != nil {
|
||||
return tx, err
|
||||
}
|
||||
@ -389,9 +392,6 @@ func (t *Transactor) validateAndBuildTransaction(rpcWrapper *rpcWrapper, args wa
|
||||
}
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), t.rpcCallTimeout)
|
||||
defer cancel()
|
||||
|
||||
gasPrice := (*big.Int)(args.GasPrice)
|
||||
// GasPrice should be estimated only for LegacyTx
|
||||
if !args.IsDynamicFeeTx() && args.GasPrice == nil {
|
||||
|
Loading…
x
Reference in New Issue
Block a user