package helpers import ( "context" "crypto/ecdsa" "errors" "fmt" "log" "math/big" "strconv" "strings" "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/guregu/null" "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" "github.com/metarare/metarare_api/models" "gorm.io/gorm" ) const _DECIMAL = 1000000000000000000 var Addr_metaRare = "" var Addr_metaFinance = "" var Addr_CollectionFactory = "" var Addr_Operator = "" var Decimal = big.NewInt(1).Exp(big.NewInt(10), big.NewInt(18), nil) type ContractSet struct { Client *ethclient.Client MetaFinance *metafinance.Metafinance MetaRare *metarare.MetaRare CollectionFactory *collectionFactory.MetaRareCollectionFactory Operator *operator.MetaRareOperator ChainID *big.Int } type ClientSet struct { RpcClient *ethclient.Client WssClient *ethclient.Client } var contractSet ContractSet var clientSet ClientSet type NFTBasic struct { Name string Symbol string OwnerAddress string } type CollectionInfo struct { Tx *types.Transaction CollectionAddress string } type EIP721 struct { *NFTBasic *CollectionInfo BaseURI string } type EIP1155 struct { *NFTBasic *CollectionInfo CustomURI string } func TypeCastingToFloat64(target *big.Int) float64 { _f := new(big.Float).SetInt(target) f, _ := _f.Float64() _div := f / _DECIMAL split := strings.Split(fmt.Sprintf("%f", _div), ".") var _c string if len(split[1]) > 5 { _c = split[0] + "." + split[1][:5] } else { _c = split[0] + "." + split[1] } result, _ := strconv.ParseFloat(_c, 64) return result } func GetBalance(address string) (float64, float64, float64) { _contracts, clientSet := UseContract() _address := common.HexToAddress(address) mf1_balance, err := _contracts.MetaFinance.BalanceOf(nil, _address) if err != nil { fmt.Printf("balance(mf1) :%s", mf1_balance.String()) } mr_balance, err := _contracts.MetaRare.BalanceOf(nil, _address) if err != nil { fmt.Printf("balance(mr) :%s", mr_balance.String()) } eth_balance, _ := clientSet.RpcClient.BalanceAt(context.Background(), _address, nil) return TypeCastingToFloat64(mf1_balance), TypeCastingToFloat64(mr_balance), TypeCastingToFloat64(eth_balance) } func GetSelectedBalance(db *gorm.DB, userID uint64, kind string, address string) (float64, float64) { _contracts, clientSet := UseContract() _address := common.HexToAddress(address) if kind == "mf" { mf1_balance, err := _contracts.MetaFinance.BalanceOf(nil, _address) if err != nil { fmt.Printf("balance(mf1) :%s", mf1_balance.String()) return 0, 0 } return TypeCastingToFloat64(mf1_balance), GetAvailableBalance(db, userID, kind, TypeCastingToFloat64(mf1_balance)) } else if kind == "mr" { mr_balance, err := _contracts.MetaRare.BalanceOf(nil, _address) if err != nil { fmt.Printf("balance(mr) :%s", mr_balance.String()) return 0, 0 } return TypeCastingToFloat64(mr_balance), GetAvailableBalance(db, userID, kind, TypeCastingToFloat64(mr_balance)) } else { eth_balance, _ := clientSet.RpcClient.BalanceAt(context.Background(), _address, nil) return TypeCastingToFloat64(eth_balance), GetAvailableBalance(db, userID, kind, TypeCastingToFloat64(eth_balance)) } } func GetAvailableBalance(db *gorm.DB, userID uint64, kind string, totalBalance float64) float64 { var _available float64 deposit := []models.Deposit{} err := db.Where("user_id = ? AND status = 'deposit'", userID).Find(&deposit).Error if errors.Is(err, gorm.ErrRecordNotFound) { return 0 } if kind == "mf" { for _, item := range deposit { if item.Mf1Price != null.FloatFrom(0) { _available += item.Mf1Price.Float64 } } } else if kind == "mr" { for _, item := range deposit { if item.MrPrice != null.FloatFrom(0) { _available += item.MrPrice.Float64 } } } else { for _, item := range deposit { if item.EthPrice != null.FloatFrom(0) { _available += item.EthPrice.Float64 } } } return (totalBalance - _available) } func TransferETH(_fromPrivateKey string, _toAddress string, amount *big.Int) (error, *types.Transaction) { _, _clientSet := UseContract() privateKey, err := crypto.HexToECDSA(_fromPrivateKey) if err != nil { log.Fatal(err) } publicKey := privateKey.Public() publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey) if !ok { log.Fatal("error casting public key to ECDSA") } fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA) nonce, err := _clientSet.RpcClient.PendingNonceAt(context.Background(), fromAddress) if err != nil { log.Fatal(err) } value := amount gasLimit := uint64(21000) gasPrice := obtainEstimatedGas(_clientSet.RpcClient, true) toAddress := common.HexToAddress(_toAddress) var data []byte tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, data) chainID, err := _clientSet.RpcClient.NetworkID(context.Background()) if err != nil { log.Fatal(err) } signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey) if err != nil { log.Fatal(err) } err = _clientSet.RpcClient.SendTransaction(context.Background(), signedTx) if err != nil { log.Fatal(err) } return nil, signedTx } func TransferMetaRare(fromPrivateKey string, toAddress string, amount *big.Int) (error, *types.Transaction) { _contracts, _clientSet := UseContract() c := make(chan types.Log) go func() { err, log := WaitTxByLog(Addr_metaRare) if err != nil { fmt.Print(err) } c <- *log }() err, auth := makeAuth(_clientSet.RpcClient, fromPrivateKey, toAddress, nil) if err != nil { return err, nil } tx, err := _contracts.MetaRare.Transfer(auth, common.HexToAddress(toAddress), amount) if err != nil { log.Fatal(err) return err, nil } <-c return nil, tx } func TransferMetaFinance(fromPrivateKey string, toAddress string, amount *big.Int) (error, *types.Transaction) { _contracts, _clientSet := UseContract() c := make(chan types.Log) go func() { err, log := WaitTxByLog(Addr_metaFinance) if err != nil { fmt.Print(err) } c <- *log }() err, auth := makeAuth(_clientSet.RpcClient, fromPrivateKey, toAddress, nil) if err != nil { return err, nil } tx, err := _contracts.MetaFinance.Transfer(auth, common.HexToAddress(toAddress), amount) if err != nil { log.Fatal(err) return err, nil } <-c return nil, tx } func CreateCollection721(info EIP721, fromPrivateKey string) (error, EIP721) { _contracts, _clientSet := UseContract() _factory := _contracts.CollectionFactory c := make(chan types.Log) go func() { err, log := WaitTxByLog(Addr_CollectionFactory) if err != nil { fmt.Print(err) } c <- *log }() err, auth := makeAuth(_clientSet.RpcClient, fromPrivateKey, Addr_CollectionFactory, nil) if err != nil { return err, EIP721{} } _operator := common.HexToAddress(Addr_Operator) tx, err := _factory.CreateMetaRareERC721Collection(auth, info.Name, info.Symbol, info.BaseURI, _operator) if err != nil { return err, EIP721{} } vLog := <-c // fmt.Println(vLog) info.CollectionInfo = &CollectionInfo{CollectionAddress: hexutil.Encode(vLog.Data[12:32])} info.Tx = tx return nil, info } func CreateCollection1155(info EIP1155, fromPrivateKey string) (error, EIP1155) { _contracts, _clientSet := UseContract() _factory := _contracts.CollectionFactory c := make(chan types.Log) go func() { err, log := WaitTxByLog(Addr_CollectionFactory) if err != nil { fmt.Print(err) } c <- *log }() err, auth := makeAuth(_clientSet.RpcClient, fromPrivateKey, Addr_CollectionFactory, nil) if err != nil { return err, EIP1155{} } _operator := common.HexToAddress(Addr_Operator) tx, err := _factory.CreateMetaRareERC1155Collection(auth, info.Name, info.Symbol, info.CustomURI, _operator) if err != nil { return err, EIP1155{} } vLog := <-c info.CollectionInfo = &CollectionInfo{CollectionAddress: hexutil.Encode(vLog.Data[12:32])} info.Tx = tx // approve _collection, err := collectionFactory.NewMetaRareERC1155Collection(common.HexToAddress(info.CollectionAddress), _clientSet.RpcClient) if err != nil { return err, EIP1155{} } go func() { err, log := WaitTxByLog(info.CollectionAddress) if err != nil { fmt.Print(err) } c <- *log }() auth.Nonce = auth.Nonce.Add(auth.Nonce, big.NewInt(1)) _, err = _collection.SetApprovalForAll(auth, common.HexToAddress(Addr_Operator), true) if err != nil { return err, EIP1155{} } <-c /// end of approve return nil, info } func RecoverAddress(hashedData [32]byte, signature [65]byte) (common.Address, error) { _contracts, _ := UseContract() var r32 [32]byte var s32 [32]byte copy(r32[:], signature[:32]) copy(s32[:], signature[32:64]) call := bind.CallOpts{} return _contracts.Operator.RecoverAddress(&call, hashedData, (signature[64] + 27), r32, s32) } type ContractType int const ( MetaRare ContractType = iota MetaFinance ) func GetAllowance(contractType ContractType, address string) (*big.Int, error) { _contractSet, _ := UseContract() options := bind.CallOpts{} if contractType == MetaRare { return _contractSet.MetaRare.Allowance(&options, common.HexToAddress(address), common.HexToAddress(Addr_Operator)) } else if contractType == MetaFinance { return _contractSet.MetaFinance.Allowance(&options, common.HexToAddress(address), common.HexToAddress(Addr_Operator)) } return nil, fmt.Errorf("Invalid contract Type") } func ApproveForERC20(contractType ContractType, fromPrivateKey string, amount *big.Int) (*types.Transaction, string, string, error) { var _tx *types.Transaction _contracts, _clientSet := UseContract() err, auth := makeAuth(_clientSet.RpcClient, fromPrivateKey, Addr_Operator, nil) if err != nil { return nil, "", "", err } if contractType == MetaRare { _tc, err := metarare.NewMetaRare(common.HexToAddress(Addr_metaRare), _clientSet.WssClient) if err != nil { return nil, "", "", err } done := make(chan *metarare.MetaRareApproval) spender := make([]common.Address, 0) address := make([]common.Address, 0) // Registor watch sub, err := _tc.WatchApproval(nil, done, spender, address) if err != nil { return nil, "", "", err } // send Transaction _tx, err = _contracts.MetaRare.Approve(auth, common.HexToAddress(Addr_Operator), amount) if err != nil { return nil, "", "", err } //detect watch for { select { case err := <-sub.Err(): fmt.Println(err) return nil, "", "", err case t := <-done: // fmt.Printf("\tMetaRare Approve spender(%s) , vlaue (%s)\n ", t.Spender.Hash().String(), t.Value.String()) return _tx, t.Spender.Hex(), t.Value.String(), nil } } } else if contractType == MetaFinance { _tc, err := metafinance.NewMetafinance(common.HexToAddress(Addr_metaFinance), _clientSet.WssClient) if err != nil { return nil, "", "", err } done := make(chan *metafinance.MetafinanceApproval) spender := make([]common.Address, 0) address := make([]common.Address, 0) // Registor watch sub, err := _tc.WatchApproval(nil, done, spender, address) if err != nil { return nil, "", "", err } // send Transaction _tx, err = _contracts.MetaFinance.Approve(auth, common.HexToAddress(Addr_Operator), amount) if err != nil { return nil, "", "", err } //detect watch for { select { case err := <-sub.Err(): fmt.Println(err) return nil, "", "", err case t := <-done: // fmt.Printf("\tMetaFinance Approve spender(%s) , vlaue (%s)\n ", t.Spender.Hash().String(), t.Value.String()) return _tx, t.Spender.Hex(), t.Value.String(), nil } } } return _tx, "", "", nil } func Order721WithMinting(_v operator.MetaRareOperatorNFTVoucher, hashedData [32]byte, fromPrivateKey string, signature [65]byte, isGenenalCollection bool) (*types.Transaction, *types.Log, error) { _contracts, _clientSet := UseContract() c := make(chan types.Log) go func() { err, log := WaitTxByLog(_v.TokenAddress.String()) if err != nil { fmt.Print(err) } c <- *log }() _operator := _contracts.Operator err, auth := makeAuth(_clientSet.RpcClient, fromPrivateKey, Addr_Operator, nil) if err != nil { return nil, nil, err } var r32 [32]byte var s32 [32]byte copy(r32[:], signature[:32]) copy(s32[:], signature[32:64]) if _v.AssetAddress.Hex() == "0x0000000000000000000000000000000000000000" { auth.Value = _v.Price } var tx *types.Transaction if isGenenalCollection { tx, err = _operator.ExcuteMintingOrderWithERC721MetaRareCollection(auth, _v, hashedData, (signature[64] + 27), r32, s32) if err != nil { return nil, nil, err } } else { tx, err = _operator.ExcuteMintingOrderWithERC721Collection(auth, _v, hashedData, (signature[64] + 27), r32, s32) if err != nil { return nil, nil, err } } vLog := <-c return tx, &vLog, nil } func Order721OnlyTransfer(_v operator.MetaRareOperatorNFTVoucher, hashedData [32]byte, fromPrivateKey string, signature [65]byte) (*types.Transaction, *types.Log, error) { _contracts, _clientSet := UseContract() c := make(chan types.Log) _operator := _contracts.Operator err, auth := makeAuth(_clientSet.RpcClient, fromPrivateKey, Addr_Operator, nil) if err != nil { return nil, nil, err } go func() { err, log := WaitTxByLog(_v.TokenAddress.String()) if err != nil { fmt.Print(err) } c <- *log }() var r32 [32]byte var s32 [32]byte copy(r32[:], signature[:32]) copy(s32[:], signature[32:64]) fmt.Println(_v.AssetAddress.Hex()) if _v.AssetAddress.Hex() == "0x0000000000000000000000000000000000000000" { auth.Value = _v.Price } tx, err := _operator.ExcuteTransferOrderWithERC721Collection(auth, _v, hashedData, (signature[64] + 27), r32, s32) if err != nil { return nil, nil, err } vLog := <-c return tx, &vLog, nil } func Order1155WithMinting(_v operator.MetaRareOperatorNFTVoucher, hashedData [32]byte, fromPrivateKey string, signature [65]byte, isGenenalCollection bool) (*types.Transaction, *types.Log, error) { _contracts, _clientSet := UseContract() c := make(chan types.Log) go func() { err, log := WaitTxByLog(_v.TokenAddress.String()) if err != nil { fmt.Print(err) } c <- *log }() _operator := _contracts.Operator err, auth := makeAuth(_clientSet.RpcClient, fromPrivateKey, Addr_Operator, nil) if err != nil { return nil, nil, err } var r32 [32]byte var s32 [32]byte copy(r32[:], signature[:32]) copy(s32[:], signature[32:64]) fmt.Println(_v.AssetAddress.Hex()) if _v.AssetAddress.Hex() == "0x0000000000000000000000000000000000000000" { auth.Value = _v.Price } var tx *types.Transaction if isGenenalCollection { // approve // d := make(chan types.Log) // go func() { // err, log := WaitTxByLog(_v.TokenAddress.Hex()) // if err != nil { // fmt.Print(err) // } // d <- *log // }() // _collection, err := collectionFactory.NewMetaRareERC1155Collection(_v.TokenAddress, _clientSet.RpcClient) // if err != nil { // return nil, nil, err // } // _, err = _collection.SetApprovalForAll(auth, common.HexToAddress(Addr_Operator), true) // if err != nil { // return nil, nil, err // } // <-d // Mint tx, err = _operator.ExcuteMintingOrderWithERC1155MetaRareCollection(auth, _v, hashedData, (signature[64] + 27), r32, s32) if err != nil { return nil, nil, err } } else { tx, err = _operator.ExcuteMintingOrderWithERC1155Collection(auth, _v, hashedData, (signature[64] + 27), r32, s32) if err != nil { return nil, nil, err } } vLog := <-c return tx, &vLog, nil // return tx, err } func Order1155OnlyTransfer(_v operator.MetaRareOperatorNFTVoucher, hashedData [32]byte, fromPrivateKey string, signature [65]byte) (*types.Transaction, *types.Log, error) { _contracts, _clientSet := UseContract() c := make(chan types.Log) _operator := _contracts.Operator err, auth := makeAuth(_clientSet.RpcClient, fromPrivateKey, Addr_Operator, nil) if err != nil { return nil, nil, err } go func() { err, log := WaitTxByLog(_v.TokenAddress.String()) if err != nil { fmt.Print(err) } c <- *log }() var r32 [32]byte var s32 [32]byte copy(r32[:], signature[:32]) copy(s32[:], signature[32:64]) if _v.AssetAddress.Hex() == "0x0000000000000000000000000000000000000000" { auth.Value = _v.Price } tx, err := _operator.ExcuteTransferOrderWithERC1155Collection(auth, _v, hashedData, (signature[64] + 27), r32, s32) if err != nil { return nil, nil, err } vLog := <-c return tx, &vLog, nil }