package commands import ( "context" "database/sql" "encoding/json" "errors" "fmt" "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/status-im/status-go/rpc" persistence "github.com/status-im/status-go/services/connector/database" "github.com/status-im/status-go/services/wallet/router/fees" "github.com/status-im/status-go/signal" "github.com/status-im/status-go/transactions" ) var ( ErrParamsFromAddressIsNotShared = errors.New("from parameter address is not dApp's shared account") ErrNoTransactionParamsFound = errors.New("no transaction in params found") ErrSendingParamsInvalid = errors.New("sending params are invalid") ) type SendTransactionCommand struct { RpcClient rpc.ClientInterface Db *sql.DB ClientHandler ClientSideHandlerInterface } func (r *RPCRequest) getSendTransactionParams() (*transactions.SendTxArgs, error) { if r.Params == nil || len(r.Params) == 0 { return nil, ErrEmptyRPCParams } paramMap, ok := r.Params[0].(map[string]interface{}) if !ok { return nil, ErrNoTransactionParamsFound } paramBytes, err := json.Marshal(paramMap) if err != nil { return nil, fmt.Errorf("error marshalling first transaction param: %v", err) } var sendTxArgs transactions.SendTxArgs err = json.Unmarshal(paramBytes, &sendTxArgs) if err != nil { return nil, fmt.Errorf("error unmarshalling first transaction param to SendTxArgs: %v", err) } return &sendTxArgs, nil } func (c *SendTransactionCommand) Execute(ctx context.Context, request RPCRequest) (interface{}, error) { err := request.Validate() if err != nil { return "", err } dApp, err := persistence.SelectDAppByUrl(c.Db, request.URL) if err != nil { return "", err } if dApp == nil { return "", ErrDAppIsNotPermittedByUser } params, err := request.getSendTransactionParams() if err != nil { return "", err } if !params.Valid() { return "", ErrSendingParamsInvalid } if params.From != dApp.SharedAccount { return "", ErrParamsFromAddressIsNotShared } if params.Value == nil { params.Value = (*hexutil.Big)(big.NewInt(0)) } if params.GasPrice == nil || (params.MaxFeePerGas == nil && params.MaxPriorityFeePerGas == nil) { feeManager := &fees.FeeManager{ RPCClient: c.RpcClient, } fetchedFees, err := feeManager.SuggestedFees(ctx, dApp.ChainID) if err != nil { return "", err } if !fetchedFees.EIP1559Enabled { params.GasPrice = (*hexutil.Big)(fetchedFees.GasPrice) } else { params.MaxFeePerGas = (*hexutil.Big)(fetchedFees.FeeFor(fees.GasFeeMedium)) params.MaxPriorityFeePerGas = (*hexutil.Big)(fetchedFees.MaxPriorityFeePerGas) } } if params.Nonce == nil { ethClient, err := c.RpcClient.EthClient(dApp.ChainID) if err != nil { return "", err } nonce, err := ethClient.PendingNonceAt(ctx, common.Address(dApp.SharedAccount)) if err != nil { return "", err } params.Nonce = (*hexutil.Uint64)(&nonce) } hash, err := c.ClientHandler.RequestSendTransaction(signal.ConnectorDApp{ URL: request.URL, Name: request.Name, IconURL: request.IconURL, }, dApp.ChainID, params) if err != nil { return "", err } return hash.String(), nil }