Compare commits
No commits in common. "05c2a102d4edf862932e1e704f4b052fa7dead21" and "7b46f30fde4fc8036f72ae85f8370882197ca85b" have entirely different histories.
05c2a102d4
...
7b46f30fde
4 changed files with 74 additions and 51 deletions
50
etherscan.go
Normal file
50
etherscan.go
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
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
|
||||||
|
}
|
18
main.go
18
main.go
|
@ -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{}, err
|
return Asset{}, nil
|
||||||
}
|
}
|
||||||
for _, a := range assets {
|
for _, a := range assets {
|
||||||
if len(a.ImageUrl) == 0 {
|
if len(a.ImageUrl) == 0 {
|
||||||
|
@ -102,17 +102,18 @@ 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.Asset.LastSale.TotalPrice * d.Asset.LastSale.PaymentToken.USDPrice
|
return d.Transaction.Value * d.Asset.LastSale.TokenUSDPrice
|
||||||
}
|
}
|
||||||
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) (string, error) {
|
func downloadOpenSeaAsset(asset Asset, transaction Transaction) (string, error) {
|
||||||
id := getOpenSeaId(asset.Id)
|
id := getOpenSeaId(asset.Id)
|
||||||
|
|
||||||
u, err := url.Parse(asset.ImageUrl)
|
u, err := url.Parse(asset.ImageUrl)
|
||||||
|
@ -142,6 +143,7 @@ func downloadOpenSeaAsset(asset Asset) (string, error) {
|
||||||
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 {
|
||||||
|
@ -188,7 +190,15 @@ func main() {
|
||||||
}
|
}
|
||||||
log.Println(asset)
|
log.Println(asset)
|
||||||
|
|
||||||
id, err := downloadOpenSeaAsset(asset)
|
transaction, err := GetTransaction(asset.LastSale.TransactionHash)
|
||||||
|
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.")
|
||||||
|
|
35
opensea.go
35
opensea.go
|
@ -2,7 +2,6 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"math"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
@ -18,17 +17,8 @@ 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
|
||||||
|
@ -43,12 +33,8 @@ 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"`
|
||||||
|
@ -74,17 +60,6 @@ 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,
|
||||||
|
@ -92,13 +67,7 @@ func GetAssets() (Assets, error) {
|
||||||
ImageUrl: a.ImageUrl,
|
ImageUrl: a.ImageUrl,
|
||||||
Name: a.Name,
|
Name: a.Name,
|
||||||
LastSale: AssetLastSale{
|
LastSale: AssetLastSale{
|
||||||
TotalPrice: totalprice,
|
TokenUSDPrice: tokenUSDPrice,
|
||||||
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,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -3,20 +3,14 @@
|
||||||
<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>
|
<p>Valor total: <span class=dinero>USD ${{ printf "%.2f" .TotalUSDValue }}</span></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>
|
<h3><a href="/nfts/{{.Id}}">{{.Asset.Name}}</a> (<span class=dinero>${{printf "%.2f" .GetUSDPrice}})</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>
|
||||||
|
|
Loading…
Reference in a new issue