Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PR for Supporting Get ETH Tx Receipt by Tx Hash #62

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: CI

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
schedule:
- cron: "42 6 * * 0"

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2

- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: "1.x"

- name: Install Dependencies
run: |
go mod download github.com/davecgh/go-spew
go mod download github.com/google/go-cmp

- name: Test
env:
ETHERSCAN_API_KEY: ${{ secrets.ETHERSCAN_API_KEY }}
run: go test -v -coverprofile=coverage.txt -covermode=count ./...

- name: Codecov
uses: codecov/[email protected]

- name: golangci-lint
uses: golangci/golangci-lint-action@v2
10 changes: 0 additions & 10 deletions .travis.yml

This file was deleted.

19 changes: 12 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
**English** | [中文](https://github.com/nanmu42/etherscan-api/blob/master/README_ZH.md)

# etherscan-api

[![Build Status](https://travis-ci.org/nanmu42/etherscan-api.svg?branch=master)](https://travis-ci.org/nanmu42/etherscan-api)
[![Go Report Card](https://goreportcard.com/badge/github.com/nanmu42/etherscan-api)](https://goreportcard.com/report/github.com/nanmu42/etherscan-api)
[![codecov](https://codecov.io/gh/nanmu42/etherscan-api/branch/master/graph/badge.svg)](https://codecov.io/gh/nanmu42/etherscan-api)
[![GoDoc](https://godoc.org/github.com/nanmu42/etherscan-api?status.svg)](https://godoc.org/github.com/nanmu42/etherscan-api)
[中文文档](https://github.com/nanmu42/etherscan-api/blob/master/README_ZH.md)
[![CI status](https://github.com/nanmu42/etherscan-api/actions/workflows/ci.yaml/badge.svg)](https://github.com/nanmu42/etherscan-api/actions)
[![codecov](https://codecov.io/gh/nanmu42/etherscan-api/branch/master/graph/badge.svg)](https://codecov.io/gh/nanmu42/etherscan-api)
[![Go Report Card](https://goreportcard.com/badge/github.com/nanmu42/etherscan-api)](https://goreportcard.com/report/github.com/nanmu42/etherscan-api)

Go bindings to the Etherscan.io API(and its families like BscScan), with nearly Full implementation(accounts, transactions, tokens, contracts, blocks, stats), full network support(Mainnet, Ropsten, Kovan, Rinkby, Goerli, Tobalaba), and only depending on standard library. :wink:
Golang client for the Etherscan.io API(and its families like BscScan), with nearly full implementation(accounts, transactions, tokens, contracts, blocks, stats), full network support(Mainnet, Ropsten, Kovan, Rinkby, Goerli, Tobalaba), and only depending on standard library. :wink:

# Usage

Create a API instance and off you go. :rocket:
```bash
go get github.com/nanmu42/etherscan-api
```

Create an API instance and off you go. :rocket:

```go
import (
Expand Down Expand Up @@ -70,6 +75,6 @@ I am not from Etherscan and I just find their service really useful, so I implem

# License

Use of this work is governed by a MIT License.
Use of this work is governed by an MIT License.

You may find a license copy in project root.
17 changes: 11 additions & 6 deletions README_ZH.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
[English](https://github.com/nanmu42/etherscan-api/blob/master/README.md) | **中文**

# etherscan-api

[![Build Status](https://travis-ci.org/nanmu42/etherscan-api.svg?branch=master)](https://travis-ci.org/nanmu42/etherscan-api)
[![Go Report Card](https://goreportcard.com/badge/github.com/nanmu42/etherscan-api)](https://goreportcard.com/report/github.com/nanmu42/etherscan-api)
[![codecov](https://codecov.io/gh/nanmu42/etherscan-api/branch/master/graph/badge.svg)](https://codecov.io/gh/nanmu42/etherscan-api)
[![GoDoc](https://godoc.org/github.com/nanmu42/etherscan-api?status.svg)](https://godoc.org/github.com/nanmu42/etherscan-api)
[English Readme](https://github.com/nanmu42/etherscan-api/blob/master/README.md)
[![CI status](https://github.com/nanmu42/etherscan-api/actions/workflows/ci.yaml/badge.svg)](https://github.com/nanmu42/etherscan-api/actions)
[![codecov](https://codecov.io/gh/nanmu42/etherscan-api/branch/master/graph/badge.svg)](https://codecov.io/gh/nanmu42/etherscan-api)
[![Go Report Card](https://goreportcard.com/badge/github.com/nanmu42/etherscan-api)](https://goreportcard.com/report/github.com/nanmu42/etherscan-api)

Etherscan.io的Golang实现
Etherscan API的Golang客户端
支持几乎所有功能(accounts, transactions, tokens, contracts, blocks, stats),
所有公共网络(Mainnet, Ropsten, Kovan, Rinkby, Goerli, Tobalaba)。
本项目只依赖于官方库。 :wink:

# Usage
# 使用方法

```bash
go get github.com/nanmu42/etherscan-api
```

填入网络选项和API Key即可开始使用。 :rocket:

Expand Down
24 changes: 17 additions & 7 deletions block.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@

package etherscan

import "strconv"
import (
"fmt"
"strconv"
)

// BlockReward gets block and uncle rewards by block number
func (c *Client) BlockReward(blockNum int) (rewards BlockRewards, err error) {
Expand All @@ -19,21 +22,28 @@ func (c *Client) BlockReward(blockNum int) (rewards BlockRewards, err error) {
return
}

// BlockNumber gets closest block number by UNIX timestamp
// BlockNumber gets the closest block number by UNIX timestamp
//
// valid closest option: before, after
func (c *Client) BlockNumber(timestamp int64, closest string) (blockNumber int, err error) {
var result string
var blockNumberStr string

param := M{
"timestamp": strconv.Itoa(int(timestamp)),
"timestamp": strconv.FormatInt(timestamp, 10),
"closest": closest,
}

err = c.call("block", "getblocknobytime", param, &result)
err = c.call("block", "getblocknobytime", param, &blockNumberStr)

if err != nil {
return
}

blockNumber, err = strconv.Atoi(blockNumberStr)
if err != nil {
err = fmt.Errorf("parsing block number %q: %w", blockNumberStr, err)
return
}

blockNum, err := strconv.ParseInt(result, 10, 64)
blockNumber = int(blockNum)
return
}
14 changes: 7 additions & 7 deletions block_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,21 @@ func TestClient_BlockReward(t *testing.T) {
}

func TestClient_BlockNumber(t *testing.T) {
//Note: All values taken from docs.etherscan.io/api-endpoints/blocks
const ans_before = 9251482
const ans_after = 9251483
// Note: All values taken from docs.etherscan.io/api-endpoints/blocks
const ansBefore = 9251482
const ansAfter = 9251483

blockNumber, err := api.BlockNumber(1578638524, "before")
noError(t, err, "api.BlockNumber")

if blockNumber != ans_before {
t.Errorf(`api.BlockNumber(1578638524, "before") not working, got %d, want %d`, blockNumber, ans_before)
if blockNumber != ansBefore {
t.Errorf(`api.BlockNumber(1578638524, "before") not working, got %d, want %d`, blockNumber, ansBefore)
}

blockNumber, err = api.BlockNumber(1578638524, "after")
noError(t, err, "api.BlockNumber")

if blockNumber != ans_after {
t.Errorf(`api.BlockNumber(1578638524,"after") not working, got %d, want %d`, blockNumber, ans_after)
if blockNumber != ansAfter {
t.Errorf(`api.BlockNumber(1578638524,"after") not working, got %d, want %d`, blockNumber, ansAfter)
}
}
10 changes: 8 additions & 2 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,14 @@ func (c *Client) call(module, action string, param map[string]interface{}, outco
err = wrapErr(err, "json unmarshal envelope")
return
}
if envelope.Status != 1 {
err = fmt.Errorf("etherscan server: %s", envelope.Message)

if module != "proxy" { //proxy calls use jsonRPC
if envelope.Status != 1 {
err = fmt.Errorf("etherscan server: %s", envelope.Message)
return
}
} else if envelope.Error != nil {
err = fmt.Errorf("etherscan server: %s", envelope.Error)
return
}

Expand Down
5 changes: 5 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
module github.com/nanmu42/etherscan-api

go 1.13

require (
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These only got added to make testing in proxy_e2e_test.go easier. I can simplify the test case by using a simpler txn receipt and test more similar to the other cases just let me know.

github.com/davecgh/go-spew v1.1.1
github.com/google/go-cmp v0.5.6
)
18 changes: 18 additions & 0 deletions proxy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright (c) 2021 LI Zhennan
*
* Use of this work is governed by a MIT License.
* You may find a license copy in project root.
*/

package etherscan

// GetTransactionReceipt gets ETH Transaction Receipt for a given transaction hash
func (c *Client) GetTransactionReceipt(txHash string) (receipt TxReceipt, err error) {
param := M{
"txhash": txHash,
}

err = c.call("proxy", "eth_getTransactionReceipt", param, &receipt)
return
}
31 changes: 31 additions & 0 deletions proxy_e2e_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright (c) 2021 LI Zhennan
*
* Use of this work is governed by a MIT License.
* You may find a license copy in project root.
*/

package etherscan

import (
"encoding/json"
"testing"

"github.com/davecgh/go-spew/spew"
"github.com/google/go-cmp/cmp"
)

func TestClient_GetTransactionReceipt(t *testing.T) {
var expectedReceipt TxReceipt
//Response grabbed from random transaction on Etherscan.io. This is a good test since it has a couple of embedded Logs
cannedResp := []byte(`{"blockHash":"0x9d4d4c6bab3dcd3b0b3a65f3b1880a9414990090da9315183b81a1b9a309b79e","blockNumber":"0xccc210","contractAddress":null,"cumulativeGasUsed":"0x35365c","effectiveGasPrice":"0x26d7dd3724","from":"0xf878c632317b5c58c88e8b7e8de6aa17bb3dfe83","gasUsed":"0x200ea","logs":[{"address":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","topics":["0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c","0x00000000000000000000000003f7724180aa6b939894b5ca4314783b0b36b329"],"data":"0x000000000000000000000000000000000000000000000000008e1bc9bf040000","blockNumber":"0xccc210","transactionHash":"0x162681c37d4e5db904b85a9953cbbe213e9631d5c928ad6b772f696aac9f67f5","transactionIndex":"0x12","blockHash":"0x9d4d4c6bab3dcd3b0b3a65f3b1880a9414990090da9315183b81a1b9a309b79e","logIndex":"0x37","removed":false},{"address":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x00000000000000000000000003f7724180aa6b939894b5ca4314783b0b36b329","0x000000000000000000000000d0dcb7a4f8cfcdb29364d621ca5d997b7eddbc46"],"data":"0x000000000000000000000000000000000000000000000000008e1bc9bf040000","blockNumber":"0xccc210","transactionHash":"0x162681c37d4e5db904b85a9953cbbe213e9631d5c928ad6b772f696aac9f67f5","transactionIndex":"0x12","blockHash":"0x9d4d4c6bab3dcd3b0b3a65f3b1880a9414990090da9315183b81a1b9a309b79e","logIndex":"0x38","removed":false},{"address":"0x8b3192f5eebd8579568a2ed41e6feb402f93f73f","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x000000000000000000000000d0dcb7a4f8cfcdb29364d621ca5d997b7eddbc46","0x000000000000000000000000f878c632317b5c58c88e8b7e8de6aa17bb3dfe83"],"data":"0x000000000000000000000000000000000000000000000000932a9ca104b8bd31","blockNumber":"0xccc210","transactionHash":"0x162681c37d4e5db904b85a9953cbbe213e9631d5c928ad6b772f696aac9f67f5","transactionIndex":"0x12","blockHash":"0x9d4d4c6bab3dcd3b0b3a65f3b1880a9414990090da9315183b81a1b9a309b79e","logIndex":"0x39","removed":false},{"address":"0xd0dcb7a4f8cfcdb29364d621ca5d997b7eddbc46","topics":["0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1"],"data":"0x0000000000000000000000000000000000000000000000f2ce932331c81806b2000000000000000000000000000000000000000000000000e5a3780b0117856d","blockNumber":"0xccc210","transactionHash":"0x162681c37d4e5db904b85a9953cbbe213e9631d5c928ad6b772f696aac9f67f5","transactionIndex":"0x12","blockHash":"0x9d4d4c6bab3dcd3b0b3a65f3b1880a9414990090da9315183b81a1b9a309b79e","logIndex":"0x3a","removed":false},{"address":"0xd0dcb7a4f8cfcdb29364d621ca5d997b7eddbc46","topics":["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822","0x00000000000000000000000003f7724180aa6b939894b5ca4314783b0b36b329","0x000000000000000000000000f878c632317b5c58c88e8b7e8de6aa17bb3dfe83"],"data":"0x000000000000000000000000000000000000000000000000000008d0e801213b000000000000000000000000000000000000000000000000008e1bc9bf040000000000000000000000000000000000000000000000000000962b7b410a0ae0650000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0xccc210","transactionHash":"0x162681c37d4e5db904b85a9953cbbe213e9631d5c928ad6b772f696aac9f67f5","transactionIndex":"0x12","blockHash":"0x9d4d4c6bab3dcd3b0b3a65f3b1880a9414990090da9315183b81a1b9a309b79e","logIndex":"0x3b","removed":false}],"logsBloom":"0x00200000000000000000000080000004000000000800000000000000000040000000000000000000000000000000000003000000080001000000000000000000000000000000000000000008000000200000000000000000000020008000000000000000000000000000000000000000000210000000000000000010000000000000000000000000100000000000000400000001000000080000004000000000000000000000000000000000000200000000001000000000000000000000000100000002001000000000000000000000000000000000001000000000000000000000200000000080000000000000000000000000000000400000000000000000","status":"0x1","to":"0x03f7724180aa6b939894b5ca4314783b0b36b329","transactionHash":"0x162681c37d4e5db904b85a9953cbbe213e9631d5c928ad6b772f696aac9f67f5","transactionIndex":"0x12","type":"0x2"}`)

json.Unmarshal(cannedResp, &expectedReceipt)

actualReceipt, err := api.GetTransactionReceipt("0x162681c37d4e5db904b85a9953cbbe213e9631d5c928ad6b772f696aac9f67f5")
noError(t, err, "api.GetTransactionReceipt")

if !cmp.Equal(expectedReceipt, actualReceipt) {
t.Errorf(`api.GetTransactionReceipt("0x162681c37d4e5db904b85a9953cbbe213e9631d5c928ad6b772f696aac9f67f5" not working, got %s, want %s`, spew.Sdump(actualReceipt), spew.Sdump(expectedReceipt))
}
}
31 changes: 30 additions & 1 deletion response.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ type Envelope struct {
// 1 for good, 0 for error
Status int `json:"status,string"`
// OK for good, other words when Status equals 0
Message string `json:"message"`
Message string `json:"message"`
Error json.RawMessage `json:"error"` //Used for JSON RPC calls (i.e. when module==proxy)
// where response lies
Result json.RawMessage `json:"result"`
}
Expand Down Expand Up @@ -136,3 +137,31 @@ type LatestPrice struct {
ETHUSD float64 `json:"ethusd,string"`
ETHUSDTimestamp Time `json:"ethusd_timestamp"`
}

type Log struct {
Address string `json:"address"`
Topics []string `json:"topics"`
Data string `json:"data"`
BlockNumber string `json:"blockNumber"`
TransactionHash string `json:"transactionHash"`
BlockHash string `json:"blockHash"`
LogIndex string `json:"logIndex"`
Removed bool `json:"removed"`
}

type TxReceipt struct {
BlockHash string `json:"blockHash"`
BlockNumber string `json:"blockNumber"`
ContractAddress string `json:"contractAddress"`
CumulativeGasUsed string `json:"cumulativeGasUsed"`
EffectiveGasPrice string `json:"effectiveGasPrice"`
From string `json:"from"`
GasUsed string `json:"gasUsed"`
Logs []Log `json:"logs"`
LogsBloom string `json:"logsBloom"`
Status string `json:"status"`
To string `json:"to"`
TransactionHash string `json:"transactionHash"`
TransactionIndex string `json:"transactionIndex"`
Type string `json:"type"`
}