Compare commits

...

4 commits

Author SHA1 Message Date
05c2a102d4 Fallar temprano si no se puede hablar a OpenSea
All checks were successful
continuous-integration/woodpecker the build was successful
2021-11-12 11:23:54 -03:00
cd9650368e Tomar precios directamente de OpenSea
No sabía que existía total_price
2021-11-12 11:21:46 -03:00
8a5dace926 index.tmpl: hacer más legible 2021-11-12 08:21:29 -03:00
0a1a5e51b6 index.tmpl: Cerrar span 2021-11-12 08:17:33 -03:00
4 changed files with 51 additions and 74 deletions

View file

@ -1,50 +0,0 @@
package main
import (
"encoding/json"
"errors"
"math"
"net/http"
"os"
"strconv"
)
type Transaction struct {
Value float64
}
func GetTransaction(id string) (Transaction, error) {
transaction := Transaction{}
key, exists := os.LookupEnv("ETHERSCAN_KEY")
if !exists {
return transaction, errors.New("No tengo ETHERSCAN_KEY, conseguir en https://etherscan.io/apis")
}
res, err := http.DefaultClient.Get("https://api.etherscan.io/api?module=proxy" +
"&action=eth_getTransactionByHash" +
"&txhash=" + id +
"&apikey=" + key)
if err != nil {
return transaction, err
}
result := struct {
Result struct {
Value string `json:"value"`
} `json:"result,omitempty"`
Error struct {
Message string `json:"message"`
} `json:"error,omitempty"`
}{}
err = json.NewDecoder(res.Body).Decode(&result)
if err != nil {
return transaction, err
}
if len(result.Error.Message) > 0 {
return transaction, errors.New(result.Error.Message)
}
parsed, err := strconv.ParseUint(result.Result.Value[2:], 16, 64)
if err != nil {
return transaction, err
}
transaction.Value = float64(parsed) / math.Pow10(18)
return transaction, nil
}

30
main.go
View file

@ -82,7 +82,7 @@ func getRandomOpenSeaAsset() (Asset, error) {
assets, err := GetAssets() assets, err := GetAssets()
if err != nil { if err != nil {
log.Println("Error hablandole a OpenSea:", err) log.Println("Error hablandole a OpenSea:", err)
return Asset{}, nil return Asset{}, err
} }
for _, a := range assets { for _, a := range assets {
if len(a.ImageUrl) == 0 { if len(a.ImageUrl) == 0 {
@ -100,20 +100,19 @@ func getRandomOpenSeaAsset() (Asset, error) {
} }
type downloadedOpenSeaAsset struct { type downloadedOpenSeaAsset struct {
Id string `json:"Id"` Id string `json:"Id"`
Asset `json:"Asset"` Asset `json:"Asset"`
Transaction `json:"Transaction"` FileName string `json:"FileName"`
FileName string `json:"FileName"`
} }
func (d downloadedOpenSeaAsset) GetUSDPrice() float64 { func (d downloadedOpenSeaAsset) GetUSDPrice() float64 {
return d.Transaction.Value * d.Asset.LastSale.TokenUSDPrice return d.Asset.LastSale.TotalPrice * d.Asset.LastSale.PaymentToken.USDPrice
} }
func (d downloadedOpenSeaAsset) IsVideo() bool { func (d downloadedOpenSeaAsset) IsVideo() bool {
return path.Ext(d.FileName) == ".mp4" return path.Ext(d.FileName) == ".mp4"
} }
func downloadOpenSeaAsset(asset Asset, transaction Transaction) (string, error) { func downloadOpenSeaAsset(asset Asset) (string, error) {
id := getOpenSeaId(asset.Id) id := getOpenSeaId(asset.Id)
u, err := url.Parse(asset.ImageUrl) u, err := url.Parse(asset.ImageUrl)
@ -141,10 +140,9 @@ func downloadOpenSeaAsset(asset Asset, transaction Transaction) (string, error)
return "", err return "", err
} }
err = json.NewEncoder(jsonFile).Encode(downloadedOpenSeaAsset{ err = json.NewEncoder(jsonFile).Encode(downloadedOpenSeaAsset{
Id: id, Id: id,
Asset: asset, Asset: asset,
Transaction: transaction, FileName: filename,
FileName: filename,
}) })
if err != nil { if err != nil {
return "", err return "", err
@ -190,15 +188,7 @@ func main() {
} }
log.Println(asset) log.Println(asset)
transaction, err := GetTransaction(asset.LastSale.TransactionHash) id, err := downloadOpenSeaAsset(asset)
if err != nil {
log.Println("Error consiguiendo transacción de Etherscan", err)
internalError(w, "Error hablandole a Etherscan.")
return
}
log.Println(transaction)
id, err := downloadOpenSeaAsset(asset, transaction)
if err != nil { if err != nil {
log.Println("Error descargando OpenSea asset", err) log.Println("Error descargando OpenSea asset", err)
internalError(w, "Error descargando NFT.") internalError(w, "Error descargando NFT.")

View file

@ -2,6 +2,7 @@ package main
import ( import (
"encoding/json" "encoding/json"
"math"
"net/http" "net/http"
"strconv" "strconv"
) )
@ -17,8 +18,17 @@ type Asset struct {
} }
type AssetLastSale struct { type AssetLastSale struct {
TokenUSDPrice float64
TransactionHash string TransactionHash string
PaymentToken
// TotalPrice has 16 decimals trimmed off if PaymentToken.decimals > 16
TotalPrice float64
}
type PaymentToken struct {
Id uint64
Symbol string
USDPrice float64
Decimals int
} }
// https://docs.opensea.io/reference/getting-assets // https://docs.opensea.io/reference/getting-assets
@ -33,8 +43,12 @@ func GetAssets() (Assets, error) {
ImageUrl string `json:"image_url"` ImageUrl string `json:"image_url"`
Name string `json:"name"` Name string `json:"name"`
LastSale struct { LastSale struct {
TotalPrice string `json:"total_price"`
PaymentToken struct { PaymentToken struct {
Id uint64 `json:"id"`
Symbol string `json:"symbol"`
USDPrice string `json:"usd_price"` USDPrice string `json:"usd_price"`
Decimals int `json:"decimals"`
} `json:"payment_token"` } `json:"payment_token"`
Transaction struct { Transaction struct {
Hash string `json:"transaction_hash"` Hash string `json:"transaction_hash"`
@ -60,6 +74,17 @@ func GetAssets() (Assets, error) {
if err != nil { if err != nil {
return assets, err return assets, err
} }
trimmed := a.LastSale.TotalPrice
decimals := a.LastSale.PaymentToken.Decimals
if a.LastSale.PaymentToken.Decimals > 16 {
trimmed = trimmed[:len(trimmed)-16]
decimals = decimals - 16
}
totalprice, err := strconv.ParseFloat(trimmed, 64)
if err != nil {
return assets, err
}
totalprice = totalprice / math.Pow10(decimals)
assets = append(assets, Asset{ assets = append(assets, Asset{
Id: strconv.FormatUint(a.Id, 10), Id: strconv.FormatUint(a.Id, 10),
TokenId: a.TokenId, TokenId: a.TokenId,
@ -67,7 +92,13 @@ func GetAssets() (Assets, error) {
ImageUrl: a.ImageUrl, ImageUrl: a.ImageUrl,
Name: a.Name, Name: a.Name,
LastSale: AssetLastSale{ LastSale: AssetLastSale{
TokenUSDPrice: tokenUSDPrice, TotalPrice: totalprice,
PaymentToken: PaymentToken{
Id: a.LastSale.PaymentToken.Id,
Symbol: a.LastSale.PaymentToken.Symbol,
Decimals: decimals,
USDPrice: tokenUSDPrice,
},
TransactionHash: a.LastSale.Transaction.Hash, TransactionHash: a.LastSale.Transaction.Hash,
}, },
}) })

View file

@ -3,14 +3,20 @@
<h1>NFTmashin</h1> <h1>NFTmashin</h1>
<p><em>Beta: las copias pueden ser eliminadas en el futuro.</em></p> <p><em>Beta: las copias pueden ser eliminadas en el futuro.</em></p>
<p>NFTs descargados: {{ .NFTNum }}</p> <p>NFTs descargados: {{ .NFTNum }}</p>
<p>Valor total: <span class=dinero>USD ${{ printf "%.2f" .TotalUSDValue }}</span></p> <p>
Valor total:
<span class=dinero>USD ${{ printf "%.2f" .TotalUSDValue }}</span>
</p>
<a style=font-size:3rem href=/copiar>¡Copiar un NFT!</a> <a style=font-size:3rem href=/copiar>¡Copiar un NFT!</a>
</section> </section>
<section> <section>
<h2>Algunos NFTs descargados</h2> <h2>Algunos NFTs descargados</h2>
{{range .NFTs}} {{range .NFTs}}
<figure> <figure>
<h3><a href="/nfts/{{.Id}}">{{.Asset.Name}}</a> (<span class=dinero>${{printf "%.2f" .GetUSDPrice}})</h3> <h3>
<a href="/nfts/{{.Id}}">{{.Asset.Name}}</a>
(<span class=dinero>${{printf "%.2f" .GetUSDPrice}}</span>)
</h3>
{{template "embed-nft" .}} {{template "embed-nft" .}}
</figure> </figure>
<hr> <hr>