github.com/diadata-org/diadata@v1.4.593/pkg/utils/assetQuotationEIP712Signer.go (about)

     1  package utils
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/ecdsa"
     6  	"crypto/elliptic"
     7  	"encoding/hex"
     8  	"fmt"
     9  	"math/big"
    10  	"time"
    11  
    12  	"github.com/ethereum/go-ethereum/common"
    13  	"github.com/ethereum/go-ethereum/common/hexutil"
    14  	"github.com/ethereum/go-ethereum/common/math"
    15  	"github.com/ethereum/go-ethereum/crypto"
    16  )
    17  
    18  type AssetQuotationSigner struct {
    19  	privateKey string
    20  	domain     TypedDataDomain
    21  	types      Types
    22  }
    23  
    24  func NewAssetQuotationSigner(privateKey string) *AssetQuotationSigner {
    25  	domain := TypedDataDomain{
    26  		Name:              "DiaData",
    27  		Version:           "1.0.0",
    28  		ChainId:           math.NewHexOrDecimal256(1),
    29  		VerifyingContract: common.HexToAddress("0x0000000000000000000000000000000000000000").Hex(),
    30  	}
    31  
    32  	types := Types{
    33  		"Message": []Type{
    34  			{Name: "Symbol", Type: "string"},
    35  			{Name: "Address", Type: "address"},
    36  			{Name: "Blockchain", Type: "string"},
    37  			{Name: "Price", Type: "uint256"},
    38  			{Name: "Time", Type: "uint256"},
    39  		},
    40  		"EIP712Domain": []Type{
    41  			{Name: "name", Type: "string"},
    42  			{Name: "version", Type: "string"},
    43  			{Name: "chainId", Type: "uint256"},
    44  			{Name: "verifyingContract", Type: "address"},
    45  		},
    46  	}
    47  	return &AssetQuotationSigner{privateKey: privateKey, domain: domain, types: types}
    48  }
    49  
    50  func (aqs *AssetQuotationSigner) Sign(symbol, address, blockchain string, price float64, time time.Time) (string, error) {
    51  
    52  	message := map[string]interface{}{
    53  		"Symbol":     symbol,
    54  		"Address":    common.HexToAddress(address).Hex(),
    55  		"Blockchain": blockchain,
    56  		"Price":      big.NewInt(int64(price * 100000000)).String(),
    57  		"Time":       big.NewInt(time.Unix()).String(),
    58  	}
    59  
    60  	typedData := TypedData{
    61  		Types:       aqs.types,
    62  		PrimaryType: "Message",
    63  		Domain:      aqs.domain,
    64  		Message:     message,
    65  	}
    66  
    67  	typedDataHash, _, err := TypedDataAndHash(typedData)
    68  	if err != nil {
    69  		return "", err
    70  	}
    71  
    72  	pk, err := hexToPrivateKey(aqs.privateKey)
    73  	if err != nil {
    74  		return "", err
    75  	}
    76  	signature, err := crypto.Sign(typedDataHash, pk)
    77  	if err != nil {
    78  		return "", err
    79  
    80  	}
    81  
    82  	var buf bytes.Buffer
    83  	buf.Write(signature)
    84  	// buf.WriteByte(1) // recovery ID
    85  	sigData := hexutil.Encode(buf.Bytes())
    86  	// fmt.Println("sigdata", sigData)
    87  
    88  	return sigData, nil
    89  }
    90  
    91  func hexToPrivateKey(hexKey string) (*ecdsa.PrivateKey, error) {
    92  	// Decode the hex string into a byte slice
    93  	keyBytes, err := hex.DecodeString(hexKey)
    94  	if err != nil {
    95  		return nil, err
    96  	}
    97  
    98  	// Parse the byte slice as a big integer
    99  	keyBigInt := new(big.Int).SetBytes(keyBytes)
   100  
   101  	// Generate a new secp256k1 elliptic curve
   102  	curve := elliptic.P256()
   103  
   104  	// Convert the big integer to a private key using the elliptic curve
   105  	privateKey := new(ecdsa.PrivateKey)
   106  	privateKey.PublicKey.Curve = curve
   107  	privateKey.D = keyBigInt
   108  	privateKey.PublicKey.X, privateKey.PublicKey.Y = curve.ScalarBaseMult(keyBytes)
   109  
   110  	// Verify that the private key is valid
   111  	if !curve.IsOnCurve(privateKey.PublicKey.X, privateKey.PublicKey.Y) {
   112  		return nil, fmt.Errorf("invalid private key")
   113  	}
   114  
   115  	return privateKey, nil
   116  }