package helpers import ( "context" "crypto/ecdsa" "encoding/json" "fmt" "log" "math/big" "strings" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethclient" "github.com/metarare/metarare_api/contracts/collectionFactory" "github.com/metarare/metarare_api/contracts/metafinance" "github.com/metarare/metarare_api/contracts/metarare" "github.com/metarare/metarare_api/contracts/operator" ) func initEthClient() (*ethclient.Client, *ethclient.Client) { v := LoadEnvs() endPoint := v.GetString("rpc.endpoint") if strings.Compare(endPoint, "") == 0 { panic("env rpc endpoint doesn't exsit") } wss_endPoint := v.GetString("rpc.wss_endpoint") if strings.Compare(wss_endPoint, "") == 0 { panic("env rpc endpoint doesn't exsit") } client, err := ethclient.Dial(endPoint) if err != nil { log.Fatal(err) } wss_client, err := ethclient.Dial(wss_endPoint) if err != nil { log.Fatal(err) } Addr_metaFinance = v.GetString("rpc.metafinance") Addr_metaRare = v.GetString("rpc.metarare") Addr_CollectionFactory = v.GetString("rpc.collectionFactory") Addr_Operator = v.GetString("rpc.operator") return client, wss_client } func getClient() (*ethclient.Client, *ethclient.Client) { if clientSet.RpcClient != nil && clientSet.WssClient != nil { return clientSet.RpcClient, clientSet.WssClient } else { return initEthClient() } } func loadSigningKey(pkey string) (*ecdsa.PrivateKey, *ecdsa.PublicKey, common.Address) { // load the signing key privateKey, err := crypto.HexToECDSA(pkey) if err != nil { log.Fatal(err) } publicKey := privateKey.Public() publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey) if !ok { log.Fatal("cannot assert type: publicKey is not of type *ecdsa.PublicKey") } fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA) return privateKey, publicKey.(*ecdsa.PublicKey), fromAddress } func obtainNonce(_client *ethclient.Client, _address common.Address) *big.Int { nonce, err := _client.PendingNonceAt(context.Background(), _address) if err != nil { log.Fatal(err) } return new(big.Int).SetUint64(nonce) } func obtainEstimatedGas(_client *ethclient.Client, _overFitting bool) *big.Int { gasPrice, err := _client.SuggestGasPrice(context.Background()) if err != nil { log.Fatal(err) } // fmt.Println("gasPrice:", gasPrice) if _overFitting { return gasPrice.Mul(gasPrice, big.NewInt(15)).Div(gasPrice, big.NewInt(10)) } return gasPrice } func UseContract() (ContractSet, ClientSet) { clientSet.RpcClient, clientSet.WssClient = getClient() //have to make smart contract instances //metarare address := common.HexToAddress(Addr_metaRare) _metaRare, err := metarare.NewMetaRare(address, clientSet.RpcClient) if err != nil { log.Fatal("Cannot make Metarare instance ", err) } //metafinance address = common.HexToAddress(Addr_metaFinance) _metaFinance, err := metafinance.NewMetafinance(address, clientSet.RpcClient) if err != nil { log.Fatal("Cannot make MetaFinance instance", err) } // some contracts address = common.HexToAddress(Addr_CollectionFactory) _factory, err := collectionFactory.NewMetaRareCollectionFactory(address, clientSet.RpcClient) if err != nil { log.Fatal("Cannot make MetaFinance instance", err) } address = common.HexToAddress(Addr_Operator) _operator, err := operator.NewMetaRareOperator(address, clientSet.RpcClient) if err != nil { log.Fatal("Cannot make MetaFinance instance", err) } contractSet.MetaFinance = _metaFinance contractSet.MetaRare = _metaRare contractSet.CollectionFactory = _factory contractSet.Operator = _operator contractSet.ChainID, err = clientSet.WssClient.ChainID(context.Background()) return contractSet, clientSet } func makeAuth(_client *ethclient.Client, fromPrivateKey string, toAddress string, ethAmount *big.Int) (error, *bind.TransactOpts) { privateKey, err := crypto.HexToECDSA(fromPrivateKey) if err != nil { return err, nil } publicKey := privateKey.Public() publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey) if !ok { log.Fatal("cannot assert type: publicKey is not of type *ecdsa.PublicKey") } fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA) auth := bind.NewKeyedTransactor(privateKey) auth.Nonce = obtainNonce(_client, fromAddress) if ethAmount != nil { auth.Value = ethAmount } else { auth.Value = big.NewInt(0) } // fmt.Println("value :", auth.Value) // auth.GasLimit = uint64(30000000) auth.GasPrice = obtainEstimatedGas(_client, true) // fmt.Println("gasPrice:", auth.GasPrice.String()) return nil, auth } func GenerateWallet() (string, string) { privateKey, err := crypto.GenerateKey() if err != nil { log.Fatal(err) } privateKeyBytes := crypto.FromECDSA(privateKey) _privateKey := hexutil.Encode(privateKeyBytes)[2:] publicKey := privateKey.Public() publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey) if !ok { log.Fatal("error casting public key to ECDSA") } _address := crypto.PubkeyToAddress(*publicKeyECDSA).Hex() return _privateKey, _address } func WaitTxByHeader(tx *types.Transaction) error { _, _clientSet := UseContract() soc := make(chan *types.Header) sub, err := _clientSet.WssClient.SubscribeNewHead(context.Background(), soc) if err != nil { return err } for { select { case err := <-sub.Err(): _ = err return err case header := <-soc: fmt.Println(header.TxHash.Hex()) tx, err := _clientSet.RpcClient.TransactionReceipt(context.Background(), tx.Hash()) if err != nil { return err } if tx.Status == 0 { sub.Unsubscribe() return nil } else if tx.Status == 1 { sub.Unsubscribe() return nil } } } } func WaitTxByLog(contractAddress string) (error, *types.Log) { _, _clientSet := UseContract() query := ethereum.FilterQuery{ Addresses: []common.Address{common.HexToAddress(contractAddress)}, } logs := make(chan types.Log) sub, err := _clientSet.WssClient.SubscribeFilterLogs(context.Background(), query, logs) if err != nil { log.Fatal(err) } for { select { case err := <-sub.Err(): log.Fatal(err) return err, nil case vLog := <-logs: sub.Unsubscribe() return nil, &vLog } } } // for code verify func signHash(data []byte) common.Hash { msg := fmt.Sprintf("\x19Ethereum Signed Message:\n%d%s", len(data), data) return crypto.Keccak256Hash([]byte(msg)) } func SignData(data []byte, strPrivKey string) ([]byte, error) { fmt.Println("Signing....") privKey, err := crypto.HexToECDSA(strPrivKey) if err != nil { return nil, err } hash := crypto.Keccak256Hash(data) fmt.Printf("hashed :%s\n", hash.String()) signature, err := crypto.Sign(hash.Bytes(), privKey) fmt.Printf("signature :%s\n", hexutil.Encode(signature)) if err != nil { return nil, err } return signature, nil } func Verify(data []byte, signature []byte) ([]byte, error) { fmt.Println("Verifing....") hash := crypto.Keccak256Hash(data) fmt.Printf("hashed :%s\n", hash.String()) fmt.Printf("signature :%s\n", hexutil.Encode(signature)) sigPublicKey, err := crypto.Ecrecover(hash.Bytes(), signature) if err != nil { return nil, err } fmt.Printf("sigPublickey: %s\n", hexutil.Encode(sigPublicKey)) return sigPublicKey, nil } func Signing(voucher operator.MetaRareOperatorNFTVoucher, pirvateKey string) ([]byte, []byte, error) { _pk, err := crypto.HexToECDSA(pirvateKey) if err != nil { fmt.Println(err) return nil, nil, err } b, err := json.Marshal(voucher) if err != nil { fmt.Println(err) return nil, nil, err } hashRaw := crypto.Keccak256(b) signature, err := crypto.Sign(hashRaw, _pk) if err != nil { fmt.Println(err) return nil, nil, err } return signature, hashRaw, nil }