Skip to content

Commit

Permalink
feat!: allowing client to set custom values for fees, nonce, gas
Browse files Browse the repository at this point in the history
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
  • Loading branch information
saledjenic committed Nov 26, 2024
1 parent ee7f4d2 commit 38e658a
Show file tree
Hide file tree
Showing 16 changed files with 424 additions and 113 deletions.
6 changes: 5 additions & 1 deletion services/connector/commands/send_transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
Expand Down
15 changes: 15 additions & 0 deletions services/wallet/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,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)
Expand Down
3 changes: 3 additions & 0 deletions services/wallet/requests/router_input_params.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
50 changes: 50 additions & 0 deletions services/wallet/requests/tx_custom_params.go
Original file line number Diff line number Diff line change
@@ -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
}
20 changes: 12 additions & 8 deletions services/wallet/router/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@ import (

// Abbreviation `WR` for the error code stands for Wallet Router
var (
ErrNotEnoughTokenBalance = &errors.ErrorResponse{Code: errors.ErrorCode("WR-001"), Details: "not enough token balance, token: %s, chainId: %d"}
ErrNotEnoughNativeBalance = &errors.ErrorResponse{Code: errors.ErrorCode("WR-002"), Details: "not enough native balance, token: %s, chainId: %d"}
ErrNativeTokenNotFound = &errors.ErrorResponse{Code: errors.ErrorCode("WR-003"), Details: "native token not found"}
ErrTokenNotFound = &errors.ErrorResponse{Code: errors.ErrorCode("WR-004"), Details: "token not found"}
ErrNoBestRouteFound = &errors.ErrorResponse{Code: errors.ErrorCode("WR-005"), Details: "no best route found"}
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"}
ErrNotEnoughTokenBalance = &errors.ErrorResponse{Code: errors.ErrorCode("WR-001"), Details: "not enough token balance, token: %s, chainId: %d"}
ErrNotEnoughNativeBalance = &errors.ErrorResponse{Code: errors.ErrorCode("WR-002"), Details: "not enough native balance, token: %s, chainId: %d"}
ErrNativeTokenNotFound = &errors.ErrorResponse{Code: errors.ErrorCode("WR-003"), Details: "native token not found"}
ErrTokenNotFound = &errors.ErrorResponse{Code: errors.ErrorCode("WR-004"), Details: "token not found"}
ErrNoBestRouteFound = &errors.ErrorResponse{Code: errors.ErrorCode("WR-005"), Details: "no best route found"}
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"}
ErrTxCustomParamsNotProvided = &errors.ErrorResponse{Code: errors.ErrorCode("WR-010"), Details: "transaction custom params not provided"}
ErrCannotCustomizeIfNoRoute = &errors.ErrorResponse{Code: errors.ErrorCode("WR-011"), Details: "cannot customize params if no route"}
ErrCannotFindPathForProvidedIdentity = &errors.ErrorResponse{Code: errors.ErrorCode("WR-012"), Details: "cannot find path for provided identity"}
)
21 changes: 16 additions & 5 deletions services/wallet/router/fees/fees.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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 {
Expand Down Expand Up @@ -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)
}

Expand Down
4 changes: 2 additions & 2 deletions services/wallet/router/pathprocessor/processor_bridge_hop.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down Expand Up @@ -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)
}
Expand Down
2 changes: 1 addition & 1 deletion services/wallet/router/pathprocessor/processor_erc1155.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
2 changes: 1 addition & 1 deletion services/wallet/router/pathprocessor/processor_erc721.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
Loading

0 comments on commit 38e658a

Please sign in to comment.