Skip to content

Commit

Permalink
add FilterTransferLog TransactionByHash
Browse files Browse the repository at this point in the history
  • Loading branch information
lizhenchun committed Dec 22, 2021
1 parent 95abef7 commit 16af0cd
Show file tree
Hide file tree
Showing 4 changed files with 182 additions and 2 deletions.
102 changes: 102 additions & 0 deletions eth/ethlog.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package eth

import (
"context"
"encoding/hex"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"math/big"
"strings"
)

const (
TokenTypeErc20 = 1
TokenTypeErc721 = 2
)

type TransferEvent struct {
Txid string
BlockNumber int64
TokenType int
ContractAddress string
From string
To string
Value string
}

func FilterTransferLog(cli *ethclient.Client, fromBlock int64, toBlock int64, contractAddresses []common.Address) ([]TransferEvent, error) {
//hex.EncodeToString(crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)")).Bytes()))
transferTopic := "ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
logs, err := cli.FilterLogs(context.Background(), ethereum.FilterQuery{
FromBlock: big.NewInt(fromBlock),
ToBlock: big.NewInt(toBlock),
Addresses: contractAddresses,
Topics: [][]common.Hash{[]common.Hash{HexToHash(transferTopic)}},
})
if err != nil {
return nil, err
}

var evts []TransferEvent
sz := len(logs)
if sz > 0 {
evts = make([]TransferEvent, 0, sz)
for i := 0; i < sz; i++ {
log := &logs[i]
topicLen := len(log.Topics)
if topicLen == 3 || topicLen == 4 {
if hex.EncodeToString(log.Topics[0].Bytes()) != transferTopic { // Transfer event
continue
}

from := parseEthLogAddress(hex.EncodeToString(log.Topics[1].Bytes()))
to := parseEthLogAddress(hex.EncodeToString(log.Topics[2].Bytes()))

var val string
var tokenType int
if topicLen == 3 { // ERC20 Transfer event
tokenType = TokenTypeErc20
val = hex.EncodeToString(log.Data)
if len(val) == 64 {
val = parseEthLogValue(val)
}
} else if topicLen == 4 { // ERC721 Transfer event
tokenType = TokenTypeErc721
val = parseEthLogValue(hex.EncodeToString(log.Topics[3].Bytes()))
}
if val != "" {
evt := TransferEvent{
Txid: log.TxHash.String(),
BlockNumber: int64(log.BlockNumber),
TokenType: tokenType,
ContractAddress: strings.ToLower(log.Address.String()),
From: from, To: to, Value: val,
}
evts = append(evts, evt)
}
}
}
}
return evts, nil
}

func parseEthLogAddress(addr string) string {
sz := len(addr)
if sz >= 40 {
return "0x" + strings.ToLower(addr[sz-40:])
} else {
return ""
}
}

func parseEthLogValue(val string) string {
value := strings.TrimLeft(val, "0")
sz := len(value)
if sz == 0 {
value = "00"
} else if sz%2 == 1 {
value = "0" + value
}
return value
}
42 changes: 42 additions & 0 deletions eth/rpcclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@ package eth

import (
"context"
"encoding/json"
"errors"
"fmt"
"github.com/ethereum/go-ethereum"
"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/ethclient"
"github.com/ethereum/go-ethereum/rpc"
"math/big"
"strconv"
)

type EthClient struct {
Expand Down Expand Up @@ -43,3 +49,39 @@ func (this *EthClient) SendRawTransaction(ctx context.Context, signedHex string)
}
return txid, err
}

type rpcTransaction struct {
tx *types.Transaction
txExtraInfo
}

type txExtraInfo struct {
BlockNumber *string `json:"blockNumber,omitempty"`
BlockHash *common.Hash `json:"blockHash,omitempty"`
From *common.Address `json:"from,omitempty"`
}

func (tx *rpcTransaction) UnmarshalJSON(msg []byte) error {
if err := json.Unmarshal(msg, &tx.tx); err != nil {
return err
}
return json.Unmarshal(msg, &tx.txExtraInfo)
}

func (this *EthClient) TransactionByHash(ctx context.Context, hash common.Hash) (tx *types.Transaction, from *common.Address, blockNumber *big.Int, err error) {
var json *rpcTransaction
err = this.client.CallContext(ctx, &json, "eth_getTransactionByHash", hash)
if err != nil {
return nil, nil, nil, err
} else if json == nil {
return nil, nil, nil, ethereum.NotFound
} else if _, r, _ := json.tx.RawSignatureValues(); r == nil {
return nil, nil, nil, fmt.Errorf("server returned transaction without signature")
}
if json.BlockNumber != nil {
if tmp, err := strconv.ParseInt(*json.BlockNumber, 0, 64); err == nil {
blockNumber = big.NewInt(tmp)
}
}
return json.tx, json.From, blockNumber, nil
}
17 changes: 17 additions & 0 deletions qa/eth/transact_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ func TestTransaction(t *testing.T) {
rq.Nil(err)

ethChainId := wallet.ChainPrivate
chainParam, err := wallet.GetEthChainParams(ethChainId)
rq.Nil(err)
hdw, err := wallet.NewHDWallet(mnemonic, "", wallet.BtcChainMainNet, ethChainId)
rq.Nil(err)

Expand Down Expand Up @@ -86,6 +88,21 @@ func TestTransaction(t *testing.T) {
b, _ := json.MarshalIndent(tx, "", " ")
fmt.Println("tx:", string(b))

fmt.Println("get transaction receipt ----------")

tx2, from, blockNumber, err := cli.TransactionByHash(context.Background(), tx.Hash())
rq.Nil(err)
rq.True(from.String() == a0)

receipt, err := cli.RpcClient.TransactionReceipt(context.Background(), tx.Hash())
rq.Nil(err)
fmt.Println("tx block number:", receipt.BlockNumber)
rq.True(receipt.BlockNumber.Cmp(blockNumber) == 0)
sig := types.MakeSigner(chainParam, receipt.BlockNumber)
msg, err := tx2.AsMessage(sig, nil)
rq.Nil(err)
fmt.Println("tx from address:", msg.From())
rq.True(msg.From().String() == a0)
}

{ // confirm transfer
Expand Down
23 changes: 21 additions & 2 deletions qa/matic/transact_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ import (
"time"
)

// faucet: https://faucet.polygon.technology/
// faucet: https://faucet.polygon.technology/
// explore: https://mumbai.polygonscan.com/
// https://polygonscan.com/

func TestTransaction(t *testing.T) {
const tetherAbi = `[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_upgradedAddress","type":"address"}],"name":"deprecate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"deprecated","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_evilUser","type":"address"}],"name":"addBlackList","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"upgradedAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balances","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"maximumFee","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"unpause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_maker","type":"address"}],"name":"getBlackListStatus","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"allowed","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"paused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"who","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"pause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getOwner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"newBasisPoints","type":"uint256"},{"name":"newMaxFee","type":"uint256"}],"name":"setParams","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"amount","type":"uint256"}],"name":"issue","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"amount","type":"uint256"}],"name":"redeem","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"remaining","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"basisPointsRate","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"isBlackListed","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_clearedUser","type":"address"}],"name":"removeBlackList","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"MAX_UINT","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_blackListedUser","type":"address"}],"name":"destroyBlackFunds","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_initialSupply","type":"uint256"},{"name":"_name","type":"string"},{"name":"_symbol","type":"string"},{"name":"_decimals","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"Issue","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"Redeem","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"newAddress","type":"address"}],"name":"Deprecate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"feeBasisPoints","type":"uint256"},{"indexed":false,"name":"maxFee","type":"uint256"}],"name":"Params","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_blackListedUser","type":"address"},{"indexed":false,"name":"_balance","type":"uint256"}],"name":"DestroyedBlackFunds","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_user","type":"address"}],"name":"AddedBlackList","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_user","type":"address"}],"name":"RemovedBlackList","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[],"name":"Pause","type":"event"},{"anonymous":false,"inputs":[],"name":"Unpause","type":"event"}]`
Expand All @@ -26,6 +28,8 @@ func TestTransaction(t *testing.T) {
rq := require.New(t)

ethChainId := wallet.ChainMaticTestnet
chainParam, err := wallet.GetEthChainParams(ethChainId)
rq.Nil(err)
mnemonic := "anger million curious give plate dizzy mobile danger era knife slush iron"
hdw, err := wallet.NewHDWallet(mnemonic, "", wallet.BtcChainMainNet, ethChainId)
rq.Nil(err)
Expand Down Expand Up @@ -91,11 +95,26 @@ func TestTransaction(t *testing.T) {
b, _ := json.MarshalIndent(tx, "", " ")
fmt.Println("tx:", string(b))

fmt.Println("get transaction receipt ----------")
time.Sleep(waitTime)

tx2, from, blockNumber, err := cli.TransactionByHash(context.Background(), tx.Hash())
rq.Nil(err)
rq.True(from.String() == a0)

receipt, err := cli.RpcClient.TransactionReceipt(context.Background(), tx.Hash())
rq.Nil(err)
fmt.Println("tx block number:", receipt.BlockNumber)
rq.True(receipt.BlockNumber.Cmp(blockNumber) == 0)
sig := types.MakeSigner(chainParam, receipt.BlockNumber)
msg, err := tx2.AsMessage(sig, nil)
rq.Nil(err)
fmt.Println("tx from address:", msg.From())
rq.True(msg.From().String() == a0)
}

{ // confirm transfer
fmt.Println("Get balance --------")
time.Sleep(waitTime)
rightBalances := []struct {
address common.Address
balance *big.Int
Expand Down

0 comments on commit 16af0cd

Please sign in to comment.