feat: removed soon-to-be-deprecated Infura client
This commit is contained in:
parent
d1f63a8d71
commit
bc33f6d54c
|
@ -28,7 +28,6 @@ import (
|
|||
"github.com/status-im/status-go/services/wallet/thirdparty/alchemy"
|
||||
"github.com/status-im/status-go/services/wallet/thirdparty/coingecko"
|
||||
"github.com/status-im/status-go/services/wallet/thirdparty/cryptocompare"
|
||||
"github.com/status-im/status-go/services/wallet/thirdparty/infura"
|
||||
"github.com/status-im/status-go/services/wallet/thirdparty/opensea"
|
||||
"github.com/status-im/status-go/services/wallet/token"
|
||||
"github.com/status-im/status-go/services/wallet/transfer"
|
||||
|
@ -110,32 +109,27 @@ func NewService(
|
|||
openseaHTTPClient := opensea.NewHTTPClient()
|
||||
openseaClient := opensea.NewClient(config.WalletConfig.OpenseaAPIKey, openseaHTTPClient)
|
||||
openseaV2Client := opensea.NewClientV2(config.WalletConfig.OpenseaAPIKey, openseaHTTPClient)
|
||||
infuraClient := infura.NewClient(config.WalletConfig.InfuraAPIKey, config.WalletConfig.InfuraAPIKeySecret)
|
||||
alchemyClient := alchemy.NewClient(config.WalletConfig.AlchemyAPIKeys)
|
||||
|
||||
// Try OpenSea, Infura, Alchemy in that order
|
||||
contractOwnershipProviders := []thirdparty.CollectibleContractOwnershipProvider{
|
||||
infuraClient,
|
||||
alchemyClient,
|
||||
}
|
||||
|
||||
accountOwnershipProviders := []thirdparty.CollectibleAccountOwnershipProvider{
|
||||
openseaClient,
|
||||
openseaV2Client,
|
||||
infuraClient,
|
||||
alchemyClient,
|
||||
}
|
||||
|
||||
collectibleDataProviders := []thirdparty.CollectibleDataProvider{
|
||||
openseaClient,
|
||||
openseaV2Client,
|
||||
infuraClient,
|
||||
alchemyClient,
|
||||
}
|
||||
|
||||
collectionDataProviders := []thirdparty.CollectionDataProvider{
|
||||
openseaClient,
|
||||
infuraClient,
|
||||
alchemyClient,
|
||||
}
|
||||
|
||||
|
|
|
@ -1,275 +0,0 @@
|
|||
package infura
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
walletCommon "github.com/status-im/status-go/services/wallet/common"
|
||||
"github.com/status-im/status-go/services/wallet/connection"
|
||||
"github.com/status-im/status-go/services/wallet/thirdparty"
|
||||
)
|
||||
|
||||
const baseURL = "https://nft.api.infura.io"
|
||||
|
||||
type Client struct {
|
||||
thirdparty.CollectibleContractOwnershipProvider
|
||||
client *http.Client
|
||||
apiKey string
|
||||
apiKeySecret string
|
||||
connectionStatus *connection.Status
|
||||
}
|
||||
|
||||
func NewClient(apiKey string, apiKeySecret string) *Client {
|
||||
if apiKey == "" {
|
||||
log.Warn("Infura API key not available")
|
||||
}
|
||||
if apiKeySecret == "" {
|
||||
log.Warn("Infura API key secret not available")
|
||||
}
|
||||
|
||||
return &Client{
|
||||
client: &http.Client{Timeout: time.Minute},
|
||||
apiKey: apiKey,
|
||||
connectionStatus: connection.NewStatus(),
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Client) doQuery(url string) (*http.Response, error) {
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.SetBasicAuth(o.apiKey, o.apiKeySecret)
|
||||
|
||||
resp, err := o.client.Do(req)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (o *Client) ID() string {
|
||||
return InfuraID
|
||||
}
|
||||
|
||||
func (o *Client) IsChainSupported(chainID walletCommon.ChainID) bool {
|
||||
switch uint64(chainID) {
|
||||
case walletCommon.EthereumMainnet, walletCommon.ArbitrumMainnet, walletCommon.EthereumGoerli, walletCommon.EthereumSepolia:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (o *Client) IsConnected() bool {
|
||||
return o.connectionStatus.IsConnected()
|
||||
}
|
||||
|
||||
func (o *Client) FetchCollectibleOwnersByContractAddress(chainID walletCommon.ChainID, contractAddress common.Address) (*thirdparty.CollectibleContractOwnership, error) {
|
||||
cursor := ""
|
||||
ownersMap := make(map[common.Address][]CollectibleOwner)
|
||||
|
||||
for {
|
||||
url := fmt.Sprintf("%s/networks/%d/nfts/%s/owners", baseURL, chainID, contractAddress.String())
|
||||
|
||||
if cursor != "" {
|
||||
url = url + "?cursor=" + cursor
|
||||
}
|
||||
|
||||
resp, err := o.doQuery(url)
|
||||
if err != nil {
|
||||
o.connectionStatus.SetIsConnected(false)
|
||||
return nil, err
|
||||
}
|
||||
o.connectionStatus.SetIsConnected(true)
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var infuraOwnership CollectibleContractOwnership
|
||||
err = json.Unmarshal(body, &infuraOwnership)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, infuraOwner := range infuraOwnership.Owners {
|
||||
ownersMap[infuraOwner.OwnerAddress] = append(ownersMap[infuraOwner.OwnerAddress], infuraOwner)
|
||||
}
|
||||
|
||||
cursor = infuraOwnership.Cursor
|
||||
|
||||
if cursor == "" {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return infuraOwnershipToCommon(contractAddress, ownersMap)
|
||||
}
|
||||
|
||||
func (o *Client) FetchAllAssetsByOwner(chainID walletCommon.ChainID, owner common.Address, cursor string, limit int) (*thirdparty.FullCollectibleDataContainer, error) {
|
||||
queryParams := url.Values{}
|
||||
|
||||
if len(cursor) > 0 {
|
||||
queryParams["cursor"] = []string{cursor}
|
||||
}
|
||||
|
||||
return o.fetchOwnedAssets(chainID, owner, queryParams, limit)
|
||||
}
|
||||
|
||||
func (o *Client) FetchAllAssetsByOwnerAndContractAddress(chainID walletCommon.ChainID, owner common.Address, contractAddresses []common.Address, cursor string, limit int) (*thirdparty.FullCollectibleDataContainer, error) {
|
||||
queryParams := url.Values{}
|
||||
|
||||
if len(cursor) > 0 {
|
||||
queryParams["cursor"] = []string{cursor}
|
||||
}
|
||||
|
||||
for _, contractAddress := range contractAddresses {
|
||||
queryParams.Add("tokenAddress", contractAddress.String())
|
||||
}
|
||||
|
||||
return o.fetchOwnedAssets(chainID, owner, queryParams, limit)
|
||||
}
|
||||
|
||||
func (o *Client) fetchOwnedAssets(chainID walletCommon.ChainID, owner common.Address, queryParams url.Values, limit int) (*thirdparty.FullCollectibleDataContainer, error) {
|
||||
assets := new(thirdparty.FullCollectibleDataContainer)
|
||||
|
||||
if len(queryParams["cursor"]) > 0 {
|
||||
assets.PreviousCursor = queryParams["cursor"][0]
|
||||
}
|
||||
assets.Provider = o.ID()
|
||||
|
||||
for {
|
||||
url := fmt.Sprintf("%s/networks/%d/accounts/%s/assets/nfts?%s", baseURL, chainID, owner.String(), queryParams.Encode())
|
||||
|
||||
resp, err := o.doQuery(url)
|
||||
if err != nil {
|
||||
o.connectionStatus.SetIsConnected(false)
|
||||
return nil, err
|
||||
}
|
||||
o.connectionStatus.SetIsConnected(true)
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// if Json is not returned there must be an error
|
||||
if !json.Valid(body) {
|
||||
return nil, fmt.Errorf("invalid json: %s", string(body))
|
||||
}
|
||||
|
||||
container := NFTList{}
|
||||
err = json.Unmarshal(body, &container)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
assets.Items = append(assets.Items, container.toCommon()...)
|
||||
assets.NextCursor = container.Cursor
|
||||
|
||||
if len(assets.NextCursor) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
queryParams["cursor"] = []string{assets.NextCursor}
|
||||
|
||||
if limit != thirdparty.FetchNoLimit && len(assets.Items) >= limit {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return assets, nil
|
||||
}
|
||||
|
||||
func (o *Client) FetchAssetsByCollectibleUniqueID(uniqueIDs []thirdparty.CollectibleUniqueID) ([]thirdparty.FullCollectibleData, error) {
|
||||
ret := make([]thirdparty.FullCollectibleData, 0, len(uniqueIDs))
|
||||
|
||||
for _, id := range uniqueIDs {
|
||||
url := fmt.Sprintf("%s/networks/%d/nfts/%s/tokens/%s", baseURL, id.ContractID.ChainID, id.ContractID.Address.String(), id.TokenID.String())
|
||||
|
||||
resp, err := o.doQuery(url)
|
||||
if err != nil {
|
||||
o.connectionStatus.SetIsConnected(false)
|
||||
return nil, err
|
||||
}
|
||||
o.connectionStatus.SetIsConnected(true)
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// if Json is not returned there must be an error
|
||||
if !json.Valid(body) {
|
||||
return nil, fmt.Errorf("invalid json: %s", string(body))
|
||||
}
|
||||
|
||||
asset := Asset{}
|
||||
err = json.Unmarshal(body, &asset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
item := asset.toCommon(id)
|
||||
|
||||
ret = append(ret, item)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (o *Client) FetchCollectionsDataByContractID(contractIDs []thirdparty.ContractID) ([]thirdparty.CollectionData, error) {
|
||||
ret := make([]thirdparty.CollectionData, 0, len(contractIDs))
|
||||
|
||||
for _, id := range contractIDs {
|
||||
url := fmt.Sprintf("%s/networks/%d/nfts/%s", baseURL, id.ChainID, id.Address.String())
|
||||
|
||||
resp, err := o.doQuery(url)
|
||||
if err != nil {
|
||||
o.connectionStatus.SetIsConnected(false)
|
||||
return nil, err
|
||||
}
|
||||
o.connectionStatus.SetIsConnected(true)
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// if Json is not returned there must be an error
|
||||
if !json.Valid(body) {
|
||||
return nil, fmt.Errorf("invalid json: %s", string(body))
|
||||
}
|
||||
|
||||
contract := ContractMetadata{}
|
||||
err = json.Unmarshal(body, &contract)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
item := contract.toCommon(id)
|
||||
|
||||
ret = append(ret, item)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
|
@ -1,188 +0,0 @@
|
|||
package infura
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
|
||||
"github.com/status-im/status-go/services/wallet/bigint"
|
||||
walletCommon "github.com/status-im/status-go/services/wallet/common"
|
||||
"github.com/status-im/status-go/services/wallet/thirdparty"
|
||||
|
||||
"golang.org/x/text/cases"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
const InfuraID = "infura"
|
||||
|
||||
func chainStringToChainID(chainString string) walletCommon.ChainID {
|
||||
chainID := walletCommon.UnknownChainID
|
||||
switch chainString {
|
||||
case "ETHEREUM":
|
||||
chainID = walletCommon.EthereumMainnet
|
||||
case "ARBITRUM":
|
||||
chainID = walletCommon.ArbitrumMainnet
|
||||
case "GOERLI":
|
||||
chainID = walletCommon.EthereumGoerli
|
||||
case "SEPOLIA":
|
||||
chainID = walletCommon.EthereumSepolia
|
||||
}
|
||||
return walletCommon.ChainID(chainID)
|
||||
}
|
||||
|
||||
type CollectibleOwner struct {
|
||||
ContractAddress common.Address `json:"tokenAddress"`
|
||||
TokenID *bigint.BigInt `json:"tokenId"`
|
||||
Amount *bigint.BigInt `json:"amount"`
|
||||
OwnerAddress common.Address `json:"ownerOf"`
|
||||
}
|
||||
|
||||
type CollectibleContractOwnership struct {
|
||||
Owners []CollectibleOwner `json:"owners"`
|
||||
Network string `json:"network"`
|
||||
Cursor string `json:"cursor"`
|
||||
}
|
||||
|
||||
func infuraOwnershipToCommon(contractAddress common.Address, ownersMap map[common.Address][]CollectibleOwner) (*thirdparty.CollectibleContractOwnership, error) {
|
||||
owners := make([]thirdparty.CollectibleOwner, 0, len(ownersMap))
|
||||
|
||||
for ownerAddress, ownerTokens := range ownersMap {
|
||||
tokenBalances := make([]thirdparty.TokenBalance, 0, len(ownerTokens))
|
||||
|
||||
for _, token := range ownerTokens {
|
||||
tokenBalances = append(tokenBalances, thirdparty.TokenBalance{
|
||||
TokenID: token.TokenID,
|
||||
Balance: token.Amount,
|
||||
})
|
||||
}
|
||||
|
||||
owners = append(owners, thirdparty.CollectibleOwner{
|
||||
OwnerAddress: ownerAddress,
|
||||
TokenBalances: tokenBalances,
|
||||
})
|
||||
}
|
||||
|
||||
ownership := thirdparty.CollectibleContractOwnership{
|
||||
ContractAddress: contractAddress,
|
||||
Owners: owners,
|
||||
}
|
||||
|
||||
return &ownership, nil
|
||||
}
|
||||
|
||||
type AttributeValue string
|
||||
|
||||
func (st *AttributeValue) UnmarshalJSON(b []byte) error {
|
||||
var item interface{}
|
||||
if err := json.Unmarshal(b, &item); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch v := item.(type) {
|
||||
case float64:
|
||||
*st = AttributeValue(strconv.FormatFloat(v, 'f', 2, 64))
|
||||
case int:
|
||||
*st = AttributeValue(strconv.Itoa(v))
|
||||
case string:
|
||||
*st = AttributeValue(v)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Attribute struct {
|
||||
TraitType string `json:"trait_type"`
|
||||
Value AttributeValue `json:"value"`
|
||||
}
|
||||
|
||||
type AssetMetadata struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Permalink string `json:"permalink"`
|
||||
ImageURL string `json:"image"`
|
||||
AnimationURL string `json:"animation_url"`
|
||||
Attributes []Attribute `json:"attributes"`
|
||||
}
|
||||
|
||||
type ContractMetadata struct {
|
||||
ContractAddress string `json:"contract"`
|
||||
Name string `json:"name"`
|
||||
Symbol string `json:"symbol"`
|
||||
TokenType string `json:"tokenType"`
|
||||
}
|
||||
|
||||
type Asset struct {
|
||||
ContractAddress common.Address `json:"contract"`
|
||||
TokenID *bigint.BigInt `json:"tokenId"`
|
||||
Metadata AssetMetadata `json:"metadata"`
|
||||
}
|
||||
|
||||
type NFTList struct {
|
||||
Total *bigint.BigInt `json:"total"`
|
||||
PageNumber int `json:"pageNumber"`
|
||||
PageSize int `json:"pageSize"`
|
||||
Network string `json:"network"`
|
||||
Account string `json:"account"`
|
||||
Cursor string `json:"cursor"`
|
||||
Assets []Asset `json:"assets"`
|
||||
}
|
||||
|
||||
func (c *Asset) toCollectiblesData(id thirdparty.CollectibleUniqueID) thirdparty.CollectibleData {
|
||||
return thirdparty.CollectibleData{
|
||||
ID: id,
|
||||
Provider: InfuraID,
|
||||
Name: c.Metadata.Name,
|
||||
Description: c.Metadata.Description,
|
||||
Permalink: c.Metadata.Permalink,
|
||||
ImageURL: c.Metadata.ImageURL,
|
||||
AnimationURL: c.Metadata.AnimationURL,
|
||||
Traits: infuraToCollectibleTraits(c.Metadata.Attributes),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Asset) toCommon(id thirdparty.CollectibleUniqueID) thirdparty.FullCollectibleData {
|
||||
return thirdparty.FullCollectibleData{
|
||||
CollectibleData: c.toCollectiblesData(id),
|
||||
CollectionData: nil,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *NFTList) toCommon() []thirdparty.FullCollectibleData {
|
||||
ret := make([]thirdparty.FullCollectibleData, 0, len(l.Assets))
|
||||
for _, asset := range l.Assets {
|
||||
id := thirdparty.CollectibleUniqueID{
|
||||
ContractID: thirdparty.ContractID{
|
||||
ChainID: chainStringToChainID(l.Network),
|
||||
Address: asset.ContractAddress,
|
||||
},
|
||||
TokenID: asset.TokenID,
|
||||
}
|
||||
item := asset.toCommon(id)
|
||||
ret = append(ret, item)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func infuraToCollectibleTraits(attributes []Attribute) []thirdparty.CollectibleTrait {
|
||||
ret := make([]thirdparty.CollectibleTrait, 0, len(attributes))
|
||||
caser := cases.Title(language.Und, cases.NoLower)
|
||||
for _, orig := range attributes {
|
||||
dest := thirdparty.CollectibleTrait{
|
||||
TraitType: strings.Replace(orig.TraitType, "_", " ", 1),
|
||||
Value: caser.String(string(orig.Value)),
|
||||
}
|
||||
|
||||
ret = append(ret, dest)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (c *ContractMetadata) toCommon(id thirdparty.ContractID) thirdparty.CollectionData {
|
||||
return thirdparty.CollectionData{
|
||||
ID: id,
|
||||
Provider: InfuraID,
|
||||
Name: c.Name,
|
||||
Traits: make(map[string]thirdparty.CollectionTrait, 0),
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue