Skip to content

Commit

Permalink
Merge pull request #2 from DiFronzo/development
Browse files Browse the repository at this point in the history
+Omni layer propery info, ERC-20 token info, and ERC-20 token holder info.
  • Loading branch information
DiFronzo authored Sep 20, 2021
2 parents 56b3b77 + a157078 commit 0fe399e
Show file tree
Hide file tree
Showing 9 changed files with 331 additions and 54 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ fmt: ## Runs go fmt (to check for go coding guidelines).

.PHONY: staticcheck
staticcheck: ## Runs static analysis to prevend bugs, foster code simplicity, performance and editor integration.
go get -u honnef.co/go/tools/cmd/staticcheck
go install honnef.co/go/tools/cmd/staticcheck@latest
staticcheck .

.PHONY: all
Expand Down
57 changes: 4 additions & 53 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
</h1>
<p align="center">Client for the blockchair.com API using GO.

<p align="center"><a href="https://github.com/DiFronzo/blockchair/releases" target="_blank"><img src="https://img.shields.io/badge/version-v0.1.0-blue?style=for-the-badge&logo=none" alt="BC-API version" /></a>&nbsp;<a href="https://golang.org/" target="_blank"><img src="https://img.shields.io/badge/GO-1.17+-00ADD8?style=for-the-badge&logo=GO" alt="go version" /></a>&nbsp;<img src="https://img.shields.io/badge/license-MIT-red?style=for-the-badge&logo=none" alt="license" />&nbsp;<img alt="code size" src="https://img.shields.io/github/languages/code-size/difronzo/blockchair?style=for-the-badge&logo=none">&nbsp;<a href="https://goreportcard.com/report/github.com/DiFronzo/blockchair" target="_blank"><img src="https://goreportcard.com/badge/github.com/DiFronzo/blockchair?style=for-the-badge&logo=none" alt="GO report" />&nbsp;<a href="https://pkg.go.dev/github.com/DiFronzo/blockchair" target="_blank"><img src="https://img.shields.io/badge/GoDoc-reference-blue?style=for-the-badge&logo=go" alt="GoDoc" /></a>&nbsp;<a href="https://github.com/DiFronzo/blockchair/actions" target="_blank"><img alt="GitHub Workflow Status" src="https://img.shields.io/github/workflow/status/difronzo/blockchair/Tests?logo=github&style=for-the-badge"/></a></p>
<p align="center"><a href="https://github.com/DiFronzo/blockchair/releases" target="_blank"><img src="https://img.shields.io/badge/version-v0.1.1-blue?style=for-the-badge&logo=none" alt="BC-API version" /></a>&nbsp;<a href="https://golang.org/" target="_blank"><img src="https://img.shields.io/badge/GO-1.17+-00ADD8?style=for-the-badge&logo=GO" alt="go version" /></a>&nbsp;<img src="https://img.shields.io/badge/license-MIT-red?style=for-the-badge&logo=none" alt="license" />&nbsp;<img alt="code size" src="https://img.shields.io/github/languages/code-size/difronzo/blockchair?style=for-the-badge&logo=none">&nbsp;<a href="https://goreportcard.com/report/github.com/DiFronzo/blockchair" target="_blank"><img src="https://goreportcard.com/badge/github.com/DiFronzo/blockchair?style=for-the-badge&logo=none" alt="GO report" />&nbsp;<a href="https://pkg.go.dev/github.com/DiFronzo/blockchair" target="_blank"><img src="https://img.shields.io/badge/GoDoc-reference-blue?style=for-the-badge&logo=go" alt="GoDoc" /></a>&nbsp;<a href="https://github.com/DiFronzo/blockchair/actions" target="_blank"><img alt="GitHub Workflow Status" src="https://img.shields.io/github/workflow/status/difronzo/blockchair/Tests?logo=github&style=for-the-badge"/></a></p>

## ⚡️ Quick start

Expand All @@ -26,59 +26,10 @@ That's all you need to know to start! 🎉

## ⚙️ Usage & Options

### `Get address for Bitcoin-like crypto`
The function `GetAddress` is used to find information regarding a specific address. The function takes two arguments, the type of crypto (string) and the address (string).
```go
package main

import (
"fmt"
"log"

"github.com/DiFronzo/blockchair"
)

func main() {
c, _ := blockchair.New()
resp, err := c.GetAddress("bitcoin", "34xp4vRoCGJym3xR7yCVPFHoCNxv4Twseo")
if err != nil {
log.Fatalln(err)
}
for i := range resp.Data{
fmt.Println(resp.Data[i].Address.Type)
}
}
```

### `Get addresses for Bitcoin-like crypto`
The function `GetAddresses` is used to find information regarding multiple addresses. The function takes two arguments, the type of crypto (string) and the addresses ([]string).
```go
package main

import (
"fmt"
"log"

"github.com/DiFronzo/blockchair"
)

func main() {
c, _ := blockchair.New()
resp, err := c.GetAddresses("bitcoin", []string{"34xp4vRoCGJym3xR7yCVPFHoCNxv4Twseo","bc1qgdjqv0av3q56jvd82tkdjpy7gdp9ut8tlqmgrpmv24sq90ecnvqqjwvw97"})
if err != nil {
log.Fatalln(err)
}
for i := range resp.Data.Addresses {
fmt.Println(resp.Data.Addresses[i].Type)
}
}
```
### `Get address for Ethereum`
The function `GetAddressEth` is used to find information regarding a specific Ethereum address. Identical to [Get address for Bitcoin-like crypto](https://github.com/DiFronzo/blockchair#get-address-for-bitcoin-like-crypto) just with the function `GetAddressEth`.

### `Get addresses for Ethereum`
The function `GetAddressesEth` is used to find information regarding multiple Ethereum addresses. Identical to [Get addresses for Bitcoin-like crypto](https://github.com/DiFronzo/blockchair#get-addresses-for-bitcoin-like-crypto) just with the function `GetAddressesEth`.
UNDER CONSTRUCTION.

For an example of usage see [here](https://github.com/DiFronzo/blockchair/blob/main/example/main.go).

### 🐳 Docker-way to quick start

UNDER CONSTRUCTION.
Expand Down
1 change: 1 addition & 0 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const (
// Errors it is a set of errors returned when working with the package.
var (
ErrTHW = errors.New("blockchair: transaction hash is wrong")
ErrERC = errors.New("blockchair: ERC-20 token is wrong")
ErrSC = errors.New("blockchair: the Bitcoin-like cryptocurrency is not supported")
ErrSCE = errors.New("blockchair: the Ethereum cryptocurrency is not supported")
ErrSCG = errors.New("blockchair: the cryptocurrency is not supported")
Expand Down
128 changes: 128 additions & 0 deletions erc20.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package blockchair

// DataErc20 includes full server response to ERC-20 request.
type DataErc20 struct {
Data Erc20 `json:"data"`
Context ContextUncle `json:"context"`
}

// DataErc20Holder includes full server response to ERC-20 holder request.
type DataErc20Holder struct {
Data map[string]Erc20HolderInfo `json:"data"`
Context HolderContext `json:"context"`
}

// Erc20HolderInfo describes the outer structure of a ERC-20 holder.
type Erc20HolderInfo struct {
Address HolderAddress `json:"address"`
Transaction []HolderTransaction `json:"transaction,omitempty"`
}

// HolderAddress the structure of one specific Ethereum address.
type HolderAddress struct {
Balance string `json:"balance,omitempty"`
BalanceApproximate int `json:"balance_approximate,omitempty"`
Received string `json:"received,omitempty"`
ReceivedApproximate int `json:"received_approximate,omitempty"`
Spent string `json:"spent,omitempty"`
SpentApproximate int `json:"spent_approximate,omitempty"`
ReceivingTransactionCount int `json:"receiving_transaction_count,omitempty"`
SpendingTransactionCount int `json:"spending_transaction_count,omitempty"`
TransactionCount int `json:"transaction_count,omitempty"`
FirstSeenReceiving string `json:"first_seen_receiving,omitempty"`
LastSeenReceiving string `json:"last_seen_receiving,omitempty"`
FirstSeenSpending string `json:"first_seen_spending,omitempty"`
LastSeenSpending string `json:"last_seen_spending,omitempty"`
}

// HolderTransaction the structure of one specific Ethereum transaction.
type HolderTransaction struct {
BlockID int `json:"block_id"`
ID int `json:"id"`
TransactionHash string `json:"transaction_hash"`
Time string `json:"time"`
TokenAddress string `json:"token_address"`
TokenName string `json:"token_name"`
TokenSymbol string `json:"token_symbol"`
TokenDecimals int `json:"token_decimals"`
Sender string `json:"sender"`
Recipient string `json:"recipient"`
Value string `json:"value"`
ValueApproximate int `json:"value_approximate"`
}

// Erc20 is the structure of one specific ERC-20 token.
type Erc20 struct {
Name string `json:"name"`
Symbol string `json:"symbol"`
Decimals int `json:"decimals"`
Time string `json:"time"`
CreatingBlockID int `json:"creating_block_id"`
CreatingTransactionHash string `json:"creating_transaction_hash"`
Transactions int `json:"transactions"`
Transactions24H int `json:"transactions_24h"`
Volume24HApproximate float32 `json:"volume_24h_approximate"`
Volume24H string `json:"volume_24h"`
Circulation string `json:"circulation"`
CirculationApproximate float32 `json:"circulation_approximate"`
MarketPriceUsd float32 `json:"market_price_usd,omitempty"`
MarketPriceBtc float32 `json:"market_price_btc,omitempty"`
MarketCapUsd float32 `json:"market_cap_usd,omitempty"`
}

// HolderContext is the structure of context for ERC-20 holder.
type HolderContext struct {
Code int `json:"code"`
Source string `json:"source"`
Limit int `json:"limit"`
Offset int `json:"offset"`
Results int `json:"results"`
State int `json:"state"`
StateLayer2 int `json:"state_layer_2"`
MarketPriceUsd float64 `json:"market_price_usd"`
Cache *Cache `json:"cache"`
API *API `json:"api"`
Server string `json:"server"`
Time float32 `json:"time"`
RenderTime float32 `json:"render_time"`
FullTime float32 `json:"full_time"`
RequestCost float32 `json:"request_cost"`
}

// GetErc20 fetch some basic information on an ERC-20 token on Ethereum.
func (c *Client) GetErc20(crypto string, token string) (*DataErc20, error) {
return c.GetErc20Adv(crypto, token, nil)
}

// GetErc20Adv fetch some basic information on an ERC-20 token on Ethereum with options.
func (c *Client) GetErc20Adv(crypto string, token string, options map[string]string) (resp *DataErc20, e error) {
if e = c.ValidateCryptoEth(crypto); e != nil {
return
}
if e = c.ValidateErc20Token(token); e != nil {
return
}

resp = &DataErc20{}
var path = crypto + "/erc-20/" + token + "/stats"
return resp, c.LoadResponse(path, resp, options)
}

// GetErc20Holder fetch some basic information on an ERC-20 token holder on Ethereum.
func (c *Client) GetErc20Holder(crypto string, token string, address string) (*DataErc20Holder, error) {
return c.GetErc20HolderAdv(crypto, token, address, nil)
}

// GetErc20HolderAdv fetch some basic information on an ERC-20 token holder on Ethereum with options.
func (c *Client) GetErc20HolderAdv(crypto string, token string, address string, options map[string]string) (resp *DataErc20Holder, e error) {
if e = c.ValidateCryptoEth(crypto); e != nil {
return
}
if e = c.ValidateErc20Tokens([]string{token, address}); e != nil {
return
}

resp = &DataErc20Holder{}
var path = crypto + "/erc-20/" + token + "/dashboards/address/" + address
return resp, c.LoadResponse(path, resp, options)
}
47 changes: 47 additions & 0 deletions erc20_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package blockchair

import "testing"

func TestGetErc20(t *testing.T) {
tests := []struct {
currency string
token string
}{
{"ethereum", "0x4a73d94683f2c9c2Aaf32ccd5723F3e243D6a654"},
{"ethereum", "0xdac17f958d2ee523a2206206994597c13d831ec7"},
{"ethereum", "0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE"},
{"ethereum", "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"},
}
for _, test := range tests {
t.Run(test.currency, func(t *testing.T) {
cl := New()
cl.APIKey = clientID
_, e := cl.GetErc20(test.currency, test.token)
if e != nil {
t.Fatal(e)
}
})
}
}

func TestGetErc20Holder(t *testing.T) {
tests := []struct {
currency string
token string
address string
}{
{"ethereum", "0x4a73d94683f2c9c2Aaf32ccd5723F3e243D6a654", "0x3282791d6fd713f1e94f4bfd565eaa78b3a0599d"},
{"ethereum", "0x68e14bb5a45b9681327e16e528084b9d962c1a39", "0x3282791d6fd713f1e94f4bfd565eaa78b3a0599d"},
{"ethereum", "0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0", "0x3282791d6fd713f1e94f4bfd565eaa78b3a0599d"},
}
for _, test := range tests {
t.Run(test.currency, func(t *testing.T) {
cl := New()
cl.APIKey = clientID
_, e := cl.GetErc20Holder(test.currency, test.token, test.address)
if e != nil {
t.Fatal(e)
}
})
}
}
57 changes: 57 additions & 0 deletions omni.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package blockchair

import "strconv"

// DataOmni includes full server response to the Omni Layer property request.
type DataOmni struct {
Data OmniInfo `json:"data"`
Context ContextOmni `json:"context"`
}

// OmniInfo describes the outer structure of the Omni Layer property.
type OmniInfo struct {
ID int `json:"id"`
Name string `json:"name"`
Category string `json:"category"`
Subcategory string `json:"subcategory"`
Description string `json:"description"`
URL string `json:"url"`
IsDivisible bool `json:"is_divisible"`
Issuer string `json:"issuer"`
CreationTransactionHash string `json:"creation_transaction_hash,omitempty"`
CreationTime string `json:"creation_time,omitempty"`
CreationBlockID int `json:"creation_block_id"`
IsIssuanceFixed bool `json:"is_issuance_fixed"`
IsIssuanceManaged bool `json:"is_issuance_managed"`
Circulation float32 `json:"circulation"`
Ecosystem int `json:"ecosystem"`
}

// ContextOmni for omni.
type ContextOmni struct {
Code int `json:"code"`
Source string `json:"source"`
Results int `json:"results"`
State int `json:"state"`
MarketPriceUsd int `json:"market_price_usd"`
Cache *Cache `json:"cache"`
API *API `json:"api"`
Server string `json:"server"`
Time float32 `json:"time"`
RenderTime float32 `json:"render_time"`
FullTime float32 `json:"full_time"`
RequestCost float32 `json:"request_cost"`
}

// GetOmni fetch some basic information on an Omni Layer (Bitcoin) property (token).
func (c *Client) GetOmni(prorertyID int64) (*DataOmni, error) {
return c.GetOmniAdv(prorertyID, nil)
}

// GetOmniAdv fetch some basic information on an Omni Layer (Bitcoin) property (token) with options.
func (c *Client) GetOmniAdv(prorertyID int64, options map[string]string) (resp *DataOmni, e error) {

resp = &DataOmni{}
var path = "bitcoin" + "/omni/dashboards/property/" + strconv.FormatInt(prorertyID, 10)
return resp, c.LoadResponse(path, resp, options)
}
26 changes: 26 additions & 0 deletions omni_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package blockchair

import (
"strconv"
"testing"
)

func TestGetOmni(t *testing.T) {
tests := []struct {
currency int64
}{
{31},
{544},
{1},
}
for _, test := range tests {
t.Run(strconv.FormatInt(test.currency, 10), func(t *testing.T) {
cl := New()
cl.APIKey = clientID
_, e := cl.GetOmni(test.currency)
if e != nil {
t.Fatal(e)
}
})
}
}
22 changes: 22 additions & 0 deletions validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,25 @@ func (c *Client) ValidateHashesEth(hashes []string) error {

return nil
}

// ValidateErc20Token validate ERC-20 token.
func (c *Client) ValidateErc20Token(token string) error {
r, _ := regexp.Compile("0x[0-9a-fA-F]{40}")
if !r.MatchString(token) {
return c.err4(ErrERC, token)
}

return nil
}

// ValidateErc20Tokens validate ERC-20 tokens.
func (c *Client) ValidateErc20Tokens(tokens []string) error {
r, _ := regexp.Compile("0x[0-9a-fA-F]{40}")
for i := range tokens {
if !r.MatchString(tokens[i]) {
return c.err4(ErrERC, tokens[i])
}
}

return nil
}
Loading

0 comments on commit 0fe399e

Please sign in to comment.