From 5139086130bd75234097fb6dea1c0e104a27a418 Mon Sep 17 00:00:00 2001 From: coolestowl <97215481+coolestowl@users.noreply.github.com> Date: Fri, 19 Jul 2024 07:28:49 +0000 Subject: [PATCH 1/5] fix: Envelope use json.Number --- client.go | 2 +- response.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client.go b/client.go index e69679a..f6ad1b8 100644 --- a/client.go +++ b/client.go @@ -172,7 +172,7 @@ func (c *Client) call(module, action string, param map[string]interface{}, outco err = wrapErr(err, "json unmarshal envelope") return } - if envelope.Status != 1 { + if envelope.Status != "1" { err = fmt.Errorf("etherscan server: %s", envelope.Message) return } diff --git a/response.go b/response.go index 5c418cf..fd523f7 100644 --- a/response.go +++ b/response.go @@ -17,7 +17,7 @@ import ( // Envelope is the carrier of nearly every response type Envelope struct { // 1 for good, 0 for error - Status int `json:"status,string"` + Status json.Number `json:"status"` // OK for good, other words when Status equals 0 Message string `json:"message"` // where response lies From 5a42fd33a8e1ec14669d49ea63dc751d20bd4926 Mon Sep 17 00:00:00 2001 From: coolestowl <97215481+coolestowl@users.noreply.github.com> Date: Fri, 19 Jul 2024 07:54:06 +0000 Subject: [PATCH 2/5] fix: convert empty string to int --- client.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client.go b/client.go index f6ad1b8..d9b469e 100644 --- a/client.go +++ b/client.go @@ -166,6 +166,8 @@ func (c *Client) call(module, action string, param map[string]interface{}, outco return } + fixedContent := bytes.ReplaceAll(content.Bytes(), []byte(`"transactionIndex":""`), []byte(`"transactionIndex":"0"`)) + var envelope Envelope err = json.Unmarshal(content.Bytes(), &envelope) if err != nil { From bd0f3728c5843e3f73fea09a81b92f54b1317280 Mon Sep 17 00:00:00 2001 From: coolestowl <97215481+coolestowl@users.noreply.github.com> Date: Fri, 19 Jul 2024 07:56:30 +0000 Subject: [PATCH 3/5] fix --- client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client.go b/client.go index d9b469e..2199ba6 100644 --- a/client.go +++ b/client.go @@ -169,7 +169,7 @@ func (c *Client) call(module, action string, param map[string]interface{}, outco fixedContent := bytes.ReplaceAll(content.Bytes(), []byte(`"transactionIndex":""`), []byte(`"transactionIndex":"0"`)) var envelope Envelope - err = json.Unmarshal(content.Bytes(), &envelope) + err = json.Unmarshal(fixedContent, &envelope) if err != nil { err = wrapErr(err, "json unmarshal envelope") return From 83d751570a1f16897d8ec6f8cf306e593a8d3265 Mon Sep 17 00:00:00 2001 From: coolestowl <97215481+coolestowl@users.noreply.github.com> Date: Sun, 26 Oct 2025 11:50:18 +0800 Subject: [PATCH 4/5] Add Timestamp field to response struct --- response.go | 1 + 1 file changed, 1 insertion(+) diff --git a/response.go b/response.go index fd523f7..834803d 100644 --- a/response.go +++ b/response.go @@ -200,6 +200,7 @@ type Log struct { Topics []string `json:"topics"` Data string `json:"data"` BlockNumber string `json:"blockNumber"` + Timestamp string `json:"timeStamp"` TransactionHash string `json:"transactionHash"` BlockHash string `json:"blockHash"` LogIndex string `json:"logIndex"` From fa6eae8630c91624234143eb0e1c54a787bf2426 Mon Sep 17 00:00:00 2001 From: owl <97215481+coolestowl@users.noreply.github.com> Date: Tue, 25 Nov 2025 03:59:04 +0000 Subject: [PATCH 5/5] feat: contract creation --- contract.go | 9 +++++++++ contract_e2e_test.go | 16 ++++++++++++++++ response.go | 11 +++++++++++ setup_e2e_test.go | 5 ++++- 4 files changed, 40 insertions(+), 1 deletion(-) diff --git a/contract.go b/contract.go index 11e9e35..3806fb2 100644 --- a/contract.go +++ b/contract.go @@ -26,3 +26,12 @@ func (c *Client) ContractSource(address string) (source []ContractSource, err er err = c.call("contract", "getsourcecode", param, &source) return } + +func (c *Client) ContractCreation(address string) (creation []ContractCreation, err error) { + param := M{ + "contractaddresses": address, + } + + err = c.call("contract", "getcontractcreation", param, &creation) + return +} diff --git a/contract_e2e_test.go b/contract_e2e_test.go index ca577e7..075e53b 100644 --- a/contract_e2e_test.go +++ b/contract_e2e_test.go @@ -8,6 +8,7 @@ package etherscan import ( + "strings" "testing" ) @@ -38,3 +39,18 @@ func TestClient_ContractSource(t *testing.T) { t.Fatalf("api.ContractSource not working, content match failed, got\n%+v", s) } } + +func TestClient_ContractCreation(t *testing.T) { + creation, err := api.ContractCreation("0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413") + noError(t, err, "api.ContractCreation") + + if len(creation) != 1 { + t.Fatalf("api.ContractCreation not working, got len %v, expect 1", len(creation)) + } + c := creation[0] + if !strings.EqualFold(c.ContractCreator, "0x793ea9692Ada1900fBd0B80FFFEc6E431fe8b391") || + c.BlockNumber != 1428757 || + c.TxHash != "0xe9ebfecc2fa10100db51a4408d18193b3ac504584b51a4e55bdef1318f0a30f9" { + t.Fatalf("api.ContractCreation not working, content match failed, got\n%+v", c) + } +} diff --git a/response.go b/response.go index 834803d..9abb2c7 100644 --- a/response.go +++ b/response.go @@ -166,6 +166,17 @@ type ContractSource struct { SwarmSource string `json:"SwarmSource"` } +// ContractCreation holds info from query for contract creation +type ContractCreation struct { + ContractAddress string `json:"contractAddress"` + ContractCreator string `json:"contractCreator"` + TxHash string `json:"txHash"` + BlockNumber int `json:"blockNumber,string"` + Timestamp Time `json:"timestamp"` + ContractFactory string `json:"contractFactory"` + CreationBytecode string `json:"creationBytecode"` +} + // ExecutionStatus holds info from query for transaction execution status type ExecutionStatus struct { // 0 = pass, 1 = error diff --git a/setup_e2e_test.go b/setup_e2e_test.go index 64f2702..ccd111d 100644 --- a/setup_e2e_test.go +++ b/setup_e2e_test.go @@ -32,7 +32,10 @@ func init() { } bucket = NewBucket(500 * time.Millisecond) - api = New(Mainnet, apiKey) + api = NewCustomized(Customization{ + BaseURL: "https://api.etherscan.io/v2/api?chainid=1&", + Key: apiKey, + }) api.Verbose = true api.BeforeRequest = func(module string, action string, param map[string]interface{}) error { bucket.Take()