github.com/status-im/status-go@v1.1.0/services/web3provider/signature.go (about)

     1  package web3provider
     2  
     3  import (
     4  	"fmt"
     5  	"math/big"
     6  
     7  	"github.com/ethereum/go-ethereum/common"
     8  	"github.com/ethereum/go-ethereum/common/hexutil"
     9  
    10  	signercore "github.com/ethereum/go-ethereum/signer/core/apitypes"
    11  	"github.com/status-im/status-go/eth-node/crypto"
    12  	"github.com/status-im/status-go/eth-node/types"
    13  	"github.com/status-im/status-go/services/rpcfilters"
    14  	"github.com/status-im/status-go/services/typeddata"
    15  	"github.com/status-im/status-go/transactions"
    16  )
    17  
    18  // signMessage checks the pwd vs the selected account and signs a message
    19  func (api *API) signMessage(data interface{}, address string, password string) (types.HexBytes, error) {
    20  	account, err := api.getVerifiedWalletAccount(address, password)
    21  	if err != nil {
    22  		return types.HexBytes{}, err
    23  	}
    24  
    25  	var dBytes []byte
    26  	switch d := data.(type) {
    27  	case string:
    28  		dBytes = []byte(d)
    29  	case []byte:
    30  		dBytes = d
    31  	case byte:
    32  		dBytes = []byte{d}
    33  	}
    34  
    35  	hash := crypto.TextHash(dBytes)
    36  
    37  	sig, err := crypto.Sign(hash, account.AccountKey.PrivateKey)
    38  	if err != nil {
    39  		return types.HexBytes{}, err
    40  	}
    41  
    42  	sig[64] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper
    43  
    44  	return types.HexBytes(sig), err
    45  }
    46  
    47  // signTypedData accepts data and password. Gets verified account and signs typed data.
    48  func (api *API) signTypedData(typed typeddata.TypedData, address string, password string) (types.HexBytes, error) {
    49  	account, err := api.getVerifiedWalletAccount(address, password)
    50  	if err != nil {
    51  		return types.HexBytes{}, err
    52  	}
    53  	chain := new(big.Int).SetUint64(api.s.config.NetworkID)
    54  	sig, err := typeddata.Sign(typed, account.AccountKey.PrivateKey, chain)
    55  	if err != nil {
    56  		return types.HexBytes{}, err
    57  	}
    58  	return types.HexBytes(sig), err
    59  }
    60  
    61  // signTypedDataV4 accepts data and password. Gets verified account and signs typed data.
    62  func (api *API) signTypedDataV4(typed signercore.TypedData, address string, password string) (types.HexBytes, error) {
    63  	account, err := api.getVerifiedWalletAccount(address, password)
    64  	if err != nil {
    65  		return types.HexBytes{}, err
    66  	}
    67  	chain := new(big.Int).SetUint64(api.s.config.NetworkID)
    68  	sig, err := typeddata.SignTypedDataV4(typed, account.AccountKey.PrivateKey, chain)
    69  	if err != nil {
    70  		return types.HexBytes{}, err
    71  	}
    72  	return types.HexBytes(sig), err
    73  }
    74  
    75  // SendTransaction creates a new transaction and waits until it's complete.
    76  func (api *API) sendTransaction(chainID uint64, sendArgs transactions.SendTxArgs, password string, requestType string) (hash types.Hash, err error) {
    77  	verifiedAccount, err := api.getVerifiedWalletAccount(sendArgs.From.String(), password)
    78  	if err != nil {
    79  		return hash, err
    80  	}
    81  
    82  	hash, _, err = api.s.transactor.SendTransactionWithChainID(chainID, sendArgs, -1, verifiedAccount)
    83  	if err != nil {
    84  		return
    85  	}
    86  
    87  	go api.s.rpcFiltersSrvc.TriggerTransactionSentToUpstreamEvent(&rpcfilters.PendingTxInfo{
    88  		Hash:    common.Hash(hash),
    89  		Type:    requestType,
    90  		From:    common.Address(sendArgs.From),
    91  		ChainID: chainID,
    92  	})
    93  
    94  	return
    95  }
    96  
    97  func (api *API) EcRecover(data hexutil.Bytes, sig hexutil.Bytes) (types.Address, error) {
    98  	if len(sig) != 65 {
    99  		return types.Address{}, fmt.Errorf("signature must be 65 bytes long")
   100  	}
   101  	if sig[64] != 27 && sig[64] != 28 {
   102  		return types.Address{}, fmt.Errorf("invalid Ethereum signature (V is not 27 or 28)")
   103  	}
   104  	sig[64] -= 27 // Transform yellow paper V from 27/28 to 0/1
   105  	hash := crypto.TextHash(data)
   106  	rpk, err := crypto.SigToPub(hash, sig)
   107  	if err != nil {
   108  		return types.Address{}, err
   109  	}
   110  	return crypto.PubkeyToAddress(*rpk), nil
   111  }