initial release
This commit is contained in:
74
internal/fetcher/alchemy.go
Normal file
74
internal/fetcher/alchemy.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package fetcher
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type AlchemyClient struct {
|
||||
apiKey string
|
||||
http *http.Client
|
||||
}
|
||||
|
||||
func NewAlchemyClient(apiKey string) *AlchemyClient {
|
||||
return &AlchemyClient{apiKey: apiKey, http: &http.Client{}}
|
||||
}
|
||||
|
||||
// FetchOwnerTokens returns tokenIDs (as strings) for the owner for a single contract.
|
||||
// network: e.g. "arb" (arbitrum one) -> uses arb-mainnet endpoint.
|
||||
func (c *AlchemyClient) FetchOwnerTokens(network, contract, owner string) ([]string, error) {
|
||||
if c.apiKey == "" {
|
||||
return nil, errors.New("missing ALCHEMY_API_KEY")
|
||||
}
|
||||
base := networkBase(network)
|
||||
if base == "" {
|
||||
return nil, fmt.Errorf("unsupported network: %s", network)
|
||||
}
|
||||
endpoint := fmt.Sprintf("%s/nft/v3/%s/getNFTsForOwner", base, c.apiKey)
|
||||
q := url.Values{}
|
||||
q.Set("owner", owner)
|
||||
q.Add("contractAddresses[]", contract)
|
||||
q.Set("withMetadata", "false")
|
||||
url := endpoint + "?" + q.Encode()
|
||||
|
||||
resp, err := c.http.Get(url)
|
||||
if err != nil { return nil, err }
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != 200 {
|
||||
return nil, fmt.Errorf("alchemy error: %s", resp.Status)
|
||||
}
|
||||
var parsed struct {
|
||||
OwnedNfts []struct {
|
||||
Id struct { TokenId string `json:"tokenId"` } `json:"id"`
|
||||
} `json:"ownedNfts"`
|
||||
}
|
||||
if err := json.NewDecoder(resp.Body).Decode(&parsed); err != nil { return nil, err }
|
||||
ids := make([]string, 0, len(parsed.OwnedNfts))
|
||||
for _, n := range parsed.OwnedNfts {
|
||||
ids = append(ids, stripHexPrefix(n.Id.TokenId))
|
||||
}
|
||||
return ids, nil
|
||||
}
|
||||
|
||||
func stripHexPrefix(s string) string {
|
||||
s = strings.TrimPrefix(s, "0x")
|
||||
// Alchemy may return hex with leading zeros; keep as-is (frontend can parse)
|
||||
return s
|
||||
}
|
||||
|
||||
func networkBase(network string) string {
|
||||
switch strings.ToLower(network) {
|
||||
case "arb", "arbitrum", "arbitrum-one":
|
||||
return "https://arb-mainnet.g.alchemy.com"
|
||||
case "arb-sepolia", "arbitrum-sepolia":
|
||||
return "https://arb-sepolia.g.alchemy.com"
|
||||
case "eth", "mainnet", "ethereum":
|
||||
return "https://eth-mainnet.g.alchemy.com"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user