Skip to content

Commit

Permalink
feat: add command to update collection on opensea
Browse files Browse the repository at this point in the history
  • Loading branch information
alephao committed Oct 22, 2021
1 parent 562ac61 commit 6935199
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 0 deletions.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,20 @@ Note: if you want to generate the metadata following the erc-1155 convention for

Check out the output in `./out/metadata/1`. If you want to change anything, you can do so by editing the values in `./out/config.yaml`.

## Usage

### OpenSea

*Update metadata of a collection on OpenSea*:

```sh
nftool opensea update \
--contract 0x0000000000000000000000000000000000000000 \
--from 0 \
--to 1000 \
--parallel 10 # make up to 10 parallel requests, depending on the number of cores your machine have
```

## Contributing

* For requests and questions, please open an issue.
Expand Down
113 changes: 113 additions & 0 deletions cmd/opensea.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package cmd

import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"runtime"
"sync"

"github.com/spf13/cobra"
)

var (
openseaCmd = &cobra.Command{
Use: "opensea",
Short: "commands to interact with opensea",
}

// opensea update metadata
openseaUpdateContractAddress string
openseaUpdateFrom int
openseaUpdateTo int
openseaUpdateMaxCores int
openseaUpdateCmd = &cobra.Command{
Use: "update",
Short: "ask opensea to update the metadata of your collection",
Run: func(cmd *cobra.Command, args []string) {
uptadeMetadataInRangeParallel(openseaUpdateContractAddress, openseaUpdateFrom, openseaUpdateTo, openseaUpdateMaxCores)
},
}
)

func init() {
// update metadata on opensea
openseaUpdateCmd.Flags().StringVar(&openseaUpdateContractAddress, "contract", "", "address of the contract in mainnet")
openseaUpdateCmd.MarkFlagRequired("contract")
openseaUpdateCmd.Flags().IntVar(&openseaUpdateFrom, "from", 0, "the starting id for a the range of ids you want to update")
openseaUpdateCmd.MarkFlagRequired("from")
openseaUpdateCmd.Flags().IntVar(&openseaUpdateTo, "to", 0, "the last id for a the range of ids you want to update")
openseaUpdateCmd.MarkFlagRequired("to")
openseaUpdateCmd.Flags().IntVar(&openseaUpdateMaxCores, "parallel", 1, "divide requests between your cpus, default: 1")
openseaCmd.AddCommand(openseaUpdateCmd)
}

func uptadeMetadataInRangeParallel(contractAddress string, from, to int, maxCores int) {
numCpu := runtime.NumCPU()
cores := min(maxCores, numCpu)

numberOfTokensToUpdate := to - from
chunkSize := numberOfTokensToUpdate / cores
fmt.Printf("cores: %d\nchunk: %d\ntotal: %d\n", cores, chunkSize, numberOfTokensToUpdate)

var wg sync.WaitGroup

for i := 0; i < cores; i++ {
wg.Add(1)

coreFrom := (i * chunkSize) + from
coreTo := coreFrom + chunkSize

go func() {
uptadeMetadataInRange(contractAddress, coreFrom, coreTo)
wg.Done()
}()
}

wg.Wait()
}

func uptadeMetadataInRange(contractAddress string, from, to int) {
for i := from; i < to; i++ {
err := updateMetadataOf(contractAddress, i)
if err != nil {
fmt.Printf("request to update #%d failed: %s\n", i, err.Error())
} else {
fmt.Printf("requested update for #%d\n", i)
}
}
}

func updateMetadataOf(contractAddress string, id int) error {
url := fmt.Sprintf("https://api.opensea.io/api/v1/asset/%s/%d/?force_update=true", contractAddress, id)

resp, err := http.Get(url)
if err != nil {
return fmt.Errorf("failed to update with contract '%s' and id '%d': %s", contractAddress, id, err.Error())
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("invalid response when trying to update with contract '%s' and id '%d': %s", contractAddress, id, err.Error())
}

b := map[string]interface{}{}
err = json.Unmarshal(body, &b)
if err != nil {
return fmt.Errorf("failed to unmarshall response when trying to update with contract '%s' and id '%d': %s", contractAddress, id, err.Error())
}

if _, ok := b["token_id"]; !ok {
return fmt.Errorf("invalid response from opensea for contract '%s' and id '%d' (the token might not exist)", contractAddress, id)
}

return nil
}

func min(a, b int) int {
if a < b {
return a
}
return b
}
4 changes: 4 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ func NewRootCmd() *cobra.Command {
rootCmd.AddCommand(imgCmd)
rootCmd.AddCommand(provenanceCmd)
rootCmd.AddCommand(metadataCmd)

rootCmd.AddCommand(openseaCmd)

rootCmd.AddCommand(versionCmd)

return rootCmd
}

Expand Down

0 comments on commit 6935199

Please sign in to comment.