eth.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. package eth
  2. import (
  3. "context"
  4. "crypto/ecdsa"
  5. "encoding/json"
  6. "fmt"
  7. "log"
  8. "math/big"
  9. "strings"
  10. "syncscan-go/erc20"
  11. "syncscan-go/model"
  12. "github.com/ethereum/go-ethereum"
  13. "github.com/ethereum/go-ethereum/common"
  14. "github.com/ethereum/go-ethereum/common/hexutil"
  15. "github.com/ethereum/go-ethereum/core/types"
  16. "github.com/ethereum/go-ethereum/crypto"
  17. "github.com/ethereum/go-ethereum/ethclient"
  18. "github.com/pkg/errors"
  19. "github.com/ybbus/jsonrpc/v2"
  20. "golang.org/x/crypto/sha3"
  21. )
  22. type Eth struct {
  23. host string
  24. client *ethclient.Client
  25. RpcClient jsonrpc.RPCClient
  26. }
  27. var LogTransferSignHash = crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))
  28. func New(rawurl string) (*Eth, error) {
  29. client, err := ethclient.Dial(rawurl)
  30. if err != nil {
  31. fmt.Printf("Failed to connect to eth: %v", err)
  32. return nil, err
  33. }
  34. rpcClient := jsonrpc.NewClient(rawurl)
  35. return &Eth{host: rawurl, client: client, RpcClient: rpcClient}, nil
  36. }
  37. func (this *Eth) GetTxByHash(hash string) (tx model.Tx, err error) {
  38. response, err := this.RpcClient.Call("eth_getTransactionByHash", hash)
  39. if err != nil {
  40. return
  41. }
  42. log.Printf("%+v\n\n\n", response.Result)
  43. err = response.GetObject(&tx)
  44. if err != nil {
  45. return
  46. }
  47. return
  48. }
  49. func (this *Eth) GetLastBlockNumber() (*big.Int, error) {
  50. header, err := this.client.HeaderByNumber(context.Background(), nil)
  51. if err != nil {
  52. return nil, err
  53. }
  54. return header.Number, nil
  55. }
  56. func (this *Eth) GetBlockByNumber(number *big.Int) (*types.Block, error) {
  57. b, err := this.client.BlockByNumber(context.Background(), number)
  58. if err != nil {
  59. return nil, err
  60. }
  61. return b, nil
  62. }
  63. const ETH = 1_000_000_000_000_000_000
  64. func getFixedReward(blockNo uint64) uint64 {
  65. if blockNo < 4370000 {
  66. return ETH * 5
  67. } else if blockNo < 7280000 {
  68. return ETH * 3
  69. } else {
  70. return ETH * 2
  71. }
  72. }
  73. // 당근을 위해 커스터마이징 된 부분
  74. func getFixedRewardForDangnn(blockNo uint64) uint64 {
  75. return ETH * 3
  76. }
  77. func (this *Eth) GetReward(b *types.Block, rts types.Receipts) (blockReward *big.Float, txFee *big.Int, uncleTotalReward *big.Float, err error) {
  78. fixedReward := getFixedRewardForDangnn(b.Number().Uint64())
  79. blockReward = big.NewFloat(float64(fixedReward))
  80. txFee = big.NewInt(0)
  81. txs := b.Transactions()
  82. for i, rt := range rts {
  83. gasUsed := big.NewInt(int64(rt.GasUsed))
  84. fee := new(big.Int).Mul(gasUsed, txs[i].GasPrice())
  85. txFee.Add(txFee, fee)
  86. }
  87. uncleCount := len(b.Uncles())
  88. if uncleCount > 2 {
  89. uncleCount = 2
  90. }
  91. uncleTotalReward = big.NewFloat(0)
  92. if uncleCount > 0 {
  93. //블럭 마이너에게 돌아가는 리워드
  94. uncleInclusionFee := (float64(fixedReward) * 0.03125) * float64(uncleCount)
  95. for i, u := range b.Uncles() {
  96. if i == 2 {
  97. break
  98. }
  99. //엉클블럭 마이너에게 돌아가는 리워드
  100. uncleReward := float64(u.Number.Uint64() - b.Number().Uint64() + 8)
  101. uncleReward *= float64(fixedReward / 8)
  102. uncleTotalReward.Add(uncleTotalReward, big.NewFloat(uncleReward))
  103. }
  104. uncleTotalReward.Add(uncleTotalReward, big.NewFloat(uncleInclusionFee))
  105. }
  106. //Fixed_Fee + Tx_Fee + Uncle_Fee
  107. blockReward.Add(blockReward, big.NewFloat(float64(txFee.Uint64())))
  108. blockReward.Add(blockReward, uncleTotalReward)
  109. return blockReward, txFee, uncleTotalReward, nil
  110. }
  111. func (this *Eth) GetTxReceipts(transactions types.Transactions) (ret types.Receipts, err error) {
  112. for _, tx := range transactions {
  113. receipt, err := this.client.TransactionReceipt(context.Background(), tx.Hash())
  114. if err != nil {
  115. return nil, err
  116. }
  117. if receipt != nil {
  118. ret = append(ret, receipt)
  119. }
  120. }
  121. return
  122. }
  123. func (this *Eth) GetTxReceipt(txhash string) (ret *types.Receipt, err error) {
  124. receipt, err := this.client.TransactionReceipt(context.Background(), common.HexToHash(txhash))
  125. if err != nil {
  126. return
  127. }
  128. if receipt != nil {
  129. ret = receipt
  130. }
  131. return
  132. }
  133. func (this *Eth) GetToken(contractAddr common.Address) (token *erc20.Erc20, err error) {
  134. token, err = erc20.NewErc20(contractAddr, this.client)
  135. return
  136. }
  137. func (this *Eth) GetUncleBlockByBlockNumberAndIndex(blockNo uint64, idx int) (interface{}, error) {
  138. b, err := this.RpcClient.Call("eth_getUncleByBlockNumberAndIndex", fmt.Sprintf("0x%x", blockNo), fmt.Sprintf("0x%x", idx))
  139. if err != nil {
  140. return "", err
  141. }
  142. return b.Result, nil
  143. }
  144. func (this *Eth) CreateWallet() (privateKey, walletAddr string) {
  145. key, err := crypto.GenerateKey()
  146. if err != nil {
  147. log.Fatal(err)
  148. }
  149. privateKeyBytes := crypto.FromECDSA(key)
  150. privateKey = hexutil.Encode(privateKeyBytes)[2:]
  151. publicKey := key.Public()
  152. publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
  153. if !ok {
  154. log.Fatal("error casting public key to ECDSA")
  155. }
  156. publicKeyBytes := crypto.FromECDSAPub(publicKeyECDSA)
  157. //log.Println(hexutil.Encode(publicKeyBytes)[4:])
  158. //address := crypto.PubkeyToAddress(*publicKeyECDSA).Hex()
  159. hash := sha3.NewLegacyKeccak256()
  160. hash.Write(publicKeyBytes[1:])
  161. walletAddr = hexutil.Encode(hash.Sum(nil)[12:])
  162. return
  163. }
  164. func (this *Eth) GetWalletAddressFromPrivateKey(privateKey string) (string, error) {
  165. if privateKey[:2] == "0x" {
  166. privateKey = privateKey[2:]
  167. }
  168. pkey, err := crypto.HexToECDSA(privateKey)
  169. if err != nil {
  170. return "", err
  171. }
  172. publicKey := pkey.Public()
  173. publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
  174. if !ok {
  175. return "", errors.New("error casting public key to ECDSA")
  176. }
  177. fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)
  178. return fromAddress.Hex(), nil
  179. }
  180. func (this *Eth) Transfer(privateKey, to string, valueInWei, gasPrice *big.Int, gasLimit uint64) (txHash string, err error) {
  181. if privateKey[:2] == "0x" {
  182. privateKey = privateKey[2:]
  183. }
  184. if to[:2] == "0x" {
  185. to = to[2:]
  186. }
  187. pkey, err := crypto.HexToECDSA(privateKey)
  188. if err != nil {
  189. return
  190. }
  191. publicKey := pkey.Public()
  192. publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
  193. if !ok {
  194. err = errors.New("error casting public key to ECDSA")
  195. }
  196. fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)
  197. nonce, err := this.getNonce(fromAddress.Hex())
  198. if err != nil {
  199. return
  200. }
  201. toAddress := common.HexToAddress(to)
  202. tx := types.NewTransaction(nonce, toAddress, valueInWei, gasLimit, gasPrice, nil)
  203. chainID, err := this.client.NetworkID(context.Background())
  204. if err != nil {
  205. return
  206. }
  207. signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), pkey)
  208. if err != nil {
  209. log.Fatal(err)
  210. }
  211. err = this.client.SendTransaction(context.Background(), signedTx)
  212. if err != nil {
  213. return
  214. }
  215. txHash = signedTx.Hash().Hex()
  216. log.Printf("tx sent: %s\n", txHash)
  217. return
  218. }
  219. func (this *Eth) getNonce(fromAddress string) (uint64, error) {
  220. resp, err := this.RpcClient.Call("eth_getTransactionCount", fromAddress, "pending")
  221. if err != nil {
  222. return 0, err
  223. }
  224. m := resp.Result.(string)
  225. nonce, err := hexutil.DecodeUint64(m)
  226. return nonce, err
  227. }
  228. func (this *Eth) GetSuggestedGasPrice() (*big.Int, error) {
  229. gasPrice, err := this.client.SuggestGasPrice(context.Background())
  230. return gasPrice, err
  231. }
  232. func (this *Eth) GetEstimatedGasLimit(tokenAddr, pkey, toAddr string, tokenAmount *big.Int) ([]byte, uint64, error) {
  233. if strings.HasPrefix(pkey, "0x") {
  234. pkey = pkey[2:]
  235. }
  236. privateKey, err := crypto.HexToECDSA(pkey)
  237. if err != nil {
  238. return nil, 0, err
  239. }
  240. publicKey := privateKey.Public()
  241. publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
  242. if !ok {
  243. err = errors.New("error casting public key to ECDSA")
  244. return nil, 0, err
  245. }
  246. fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)
  247. toAddress := common.HexToAddress(toAddr)
  248. tokenAddress := common.HexToAddress(tokenAddr)
  249. transferFnSignature := []byte("transfer(address,uint256)")
  250. hash := sha3.NewLegacyKeccak256()
  251. hash.Write(transferFnSignature)
  252. methodID := hash.Sum(nil)[:4]
  253. paddedAddress := common.LeftPadBytes(toAddress.Bytes(), 32)
  254. paddedAmount := common.LeftPadBytes(tokenAmount.Bytes(), 32)
  255. var data []byte
  256. data = append(data, methodID...)
  257. data = append(data, paddedAddress...)
  258. data = append(data, paddedAmount...)
  259. gasLimit, err := this.client.EstimateGas(context.Background(), ethereum.CallMsg{
  260. From: fromAddress,
  261. To: &tokenAddress,
  262. Data: data,
  263. })
  264. return data, gasLimit, err
  265. }
  266. func (this *Eth) TransferToken(tokenAddr, pkey, toAddr string, tokenAmount *big.Int, gasPrice *big.Int, gasLimit uint64) (txHash string, err error) {
  267. if strings.HasPrefix(pkey, "0x") {
  268. pkey = pkey[2:]
  269. }
  270. privateKey, err := crypto.HexToECDSA(pkey)
  271. if err != nil {
  272. return "", err
  273. }
  274. publicKey := privateKey.Public()
  275. publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
  276. if !ok {
  277. err = errors.New("error casting public key to ECDSA")
  278. return "", err
  279. }
  280. fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)
  281. nonce, err := this.getNonce(fromAddress.Hex())
  282. if err != nil {
  283. return "", err
  284. }
  285. value := big.NewInt(0) // in wei (0 eth)
  286. tokenAddress := common.HexToAddress(tokenAddr)
  287. data, _, err := this.GetEstimatedGasLimit(tokenAddr, pkey, toAddr, tokenAmount)
  288. if err != nil {
  289. return "", err
  290. }
  291. v := &transferValue{
  292. nonce: nonce,
  293. gasLimit: gasLimit,
  294. gasPrice: gasPrice,
  295. }
  296. log.Printf("nonce: %d, gas price: %d, gas limit: %d\n", nonce, v.gasPrice, v.gasLimit) // 25624
  297. //gasPrice = gasPrice.Add(gasPrice, big.NewInt(100_000_000))
  298. //gasPrice = big.NewInt(5320000000)
  299. tx := types.NewTransaction(v.nonce, tokenAddress, value, v.gasLimit, v.gasPrice, data)
  300. chainID, err := this.client.NetworkID(context.Background())
  301. if err != nil {
  302. return "", err
  303. }
  304. signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
  305. if err != nil {
  306. return "", err
  307. }
  308. err = this.client.SendTransaction(context.Background(), signedTx)
  309. if err != nil {
  310. return "", err
  311. }
  312. return signedTx.Hash().Hex(), nil
  313. }
  314. func (this *Eth) GetTokenBalance(tokenAddress, address string) (balance *big.Int, err error) {
  315. token, err := this.GetToken(common.HexToAddress(tokenAddress))
  316. b, err := token.BalanceOf(nil, common.HexToAddress(address))
  317. //token.Transfer(&bind.TransactOpts{
  318. // From: common.Address{},
  319. // Nonce: nil,
  320. // Signer: nil,
  321. // Value: nil,
  322. // GasPrice: nil,
  323. // GasFeeCap: nil,
  324. // GasTipCap: nil,
  325. // GasLimit: 0,
  326. // Context: nil,
  327. // NoSend: false,
  328. //}, common.HexToAddress(address), big.NewInt(100))
  329. return b, err
  330. }
  331. func (this *Eth) GetBalance(address string) (balance *big.Int, err error) {
  332. resp, err := this.RpcClient.Call("eth_getBalance", address, "latest")
  333. if err != nil {
  334. return
  335. }
  336. b, _ := new(big.Int).SetString(resp.Result.(string)[2:], 16)
  337. return b, nil
  338. }
  339. func (this *Eth) GetInternalTxsByHash(blockNo uint64, txHash string) (calls []model.Call, err error) {
  340. lastestBlockNo, err := this.GetLastBlockNumber()
  341. if err != nil {
  342. return
  343. }
  344. args := make([]interface{}, 0)
  345. args = append(args, txHash)
  346. args = append(args, map[string]interface {
  347. }{
  348. "tracer": "callTracer",
  349. "reexec": lastestBlockNo.Uint64() - blockNo + 20,
  350. })
  351. resp, err := this.RpcClient.Call("debug_traceTransaction", args)
  352. if err != nil {
  353. return nil, err
  354. }
  355. data, _ := json.Marshal(resp.Result)
  356. log.Println(string(data))
  357. m, ok := resp.Result.(map[string]interface{})
  358. if !ok {
  359. return
  360. }
  361. data, err = json.Marshal(m["calls"])
  362. if err != nil {
  363. return
  364. }
  365. err = json.Unmarshal(data, &calls)
  366. if err != nil {
  367. return
  368. }
  369. return
  370. }