Skip to content

Commit

Permalink
Collections migration (samuelvanderwaal#126)
Browse files Browse the repository at this point in the history
* feat(collections): add collections migration command

* feat(collections): support retrying migrations from a cache file

* refactor(mint): update spl_associated_token_account imports

* style: remove println

* docs: update docs

* refactor(collections): fix clippy lints
  • Loading branch information
samuelvanderwaal authored May 22, 2022
1 parent a3b56a2 commit c64aeeb
Show file tree
Hide file tree
Showing 34 changed files with 1,526 additions and 383 deletions.
1,060 changes: 741 additions & 319 deletions Cargo.lock

Large diffs are not rendered by default.

16 changes: 10 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
[package]
name = "metaboss"
version = "0.6.1"
version = "0.6.2"
edition = "2021"
description="The Metaplex NFT-standard Swiss Army Knife tool."
repository="https://github.com/samuelvanderwaal/metaboss"
license = "Apache-2.0"

[dependencies]
metaboss_lib = "0.0.2"
metaboss_lib = "0.0.4"
anyhow = "1.0.44"
anchor-client = "0.19.0"
borsh = "0.9.1"
bs58 = "0.4.0"
console = "0.15.0"
dialoguer = "0.10.1"
env_logger = "0.9.0"
glob = "0.3.0"
indexmap = { version = "1.8.1", features = ["serde"] }
indicatif = { version = "0.16.2", features = ["rayon"] }
lazy_static = "1.4.0"
log = "0.4.14"
Expand All @@ -27,15 +30,16 @@ retry = "1.3.0"
serde = "1.0.130"
serde_json = "1.0.68"
serde_yaml = "0.8.21"
solana-account-decoder = "1.8.0"
solana-client = "1.8.1"
solana-program = "1.8.0"
solana-sdk = "1.8.0"
solana-client = "1.10.17"
solana-account-decoder = "1.10.17"
spl-associated-token-account = "1.0.3"
solana-program = "1.10.17"
solana-sdk = "1.10.17"
spl-token = "3.2.0"
structopt = "0.3.23"
thiserror = "1.0.30"
shellexpand = "2.1.0"
tokio = "1.14.1"

[features]

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ git checkout main
Install or build with Rust:

```bash
cargo install --path ./
cargo install --locked --path ./
```

or
Expand Down
1 change: 1 addition & 0 deletions docs-src/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- [Examples](./examples.md)
- [Global Options](./global_options.md)
- [Burn](./burn.md)
- [Collections](./collections.md)
- [Decode](./decode.md)
- [Derive](./derive.md)
- [Mint](./mint.md)
Expand Down
91 changes: 91 additions & 0 deletions docs-src/src/collections.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
## Collections

### Migrate

Migrate a collection of NFTs to be part of a single on-chain Metaplex Certified Collection (MCC).

1. Create your Collection Parent NFT using a minting tool such as [justmint](https://justmint.xyz/) or [NFT Armory](https://www.nftarmory.me/). Alternately, use `metaboss mint one`. This NFT will have your collection name, cover art, description, traits etc. It's the parent NFT for you collection and all items in your collection will point to this mint account.

2. Get your mint list. If your collection is a single candy machine you can use the `--candy-machine-id` option, otherwise provide the path to your mint list formatted as a JSON file with the `--mint-list` option.

Example contents of the mint list file:

```json
[
"D5ycm2mgBWDR37QVkvM389x84V4ux48bSeHLeiHPtX28",
"4kYdMRRYtXjmkusgKEBntSXLDhqkHNE57GF3RPdtx6MW",
"J8xuCFCeBRESoXewtMwrrpVUGikUG3B1WznNdLffyymz",
"4gRtRjrbD7g5ZKUvSVA1tYMK9LZqz6uWuSc3rKeinySh"
]
```

Your Collection Parent NFT must have the *same update authority* as the items you will put in the collection. If you don't want to connect your update authority keypair to a website, you can mint with a different keypair and then change the update authority with Metaboss, or mint with Metaboss's `mint one` command.

### Running the Commands

#### Single Candy Machine Collection

Let's say you've created a parent NFT for your collection with a mint address of `9wtpdjMysSphxipTSJi7pYWGzSZFm2PRFtQucJiiXUzq` and you have a candy machine id of `8yuhovH7fb63ed7Q3rcxL3kYZDhps4qspjaxx1N8WSni` and your update authority is in the file `my_keypair.json` in the same directory you are running the command. Your Metaboss command would be:

```bash
metaboss collections migrate -k my_keypair.json -c 8yuhovH7fb63ed7Q3rcxL3kYZDhps4qspjaxx1N8WSni --mint-address 9wtpdjMysSphxipTSJi7pYWGzSZFm2PRFtQucJiiXUzq
```

#### Using a Mint List File

Assume the same scenario above but with a mint list file named "my_mint_list.json" in the same directory you are running the command. Your Metaboss command would be:

```bash
metaboss collections migrate -k my_keypair.json -L my_mint_list.json --mint-address 9wtpdjMysSphxipTSJi7pYWGzSZFm2PRFtQucJiiXUzq
```

This assumes you have your RPC set in your [Solana config](https://docs.solana.com/cli/choose-a-cluster), otherwise it can be passed in with the `-r` option. As with all Metaboss commands, if you've set your keypair in your Solana config, you can omit the `-k` option. I recommend setting both in the Solana config to simplify commands:

```
solana config set --url <rpc url> --keypair <path to keypair file>
```



#### Retry Flow and Cache File

The `migrate` command rapidly fires off a lot of network requests to try to migrate over your collection as quickly as possible. If some of them fail, it keeps track of them and will give you an option to retry them. You can press "y" to retry the failed migrations or "n" to stop trying. When you press "n" it will write all remaining migrations to a cache file so you can retry them later.

![retry flow](retry_flow.png)

To retry from a cache file, you can use the `--cache-file` option.

```metaboss
metaboss collections migrate -k my_keypair.json --cache-file metaboss-cache-migrate-collections.json --mint-address 9wtpdjMysSphxipTSJi7pYWGzSZFm2PRFtQucJiiXUzq
```

This will read the items from the cache file and retry them.

When retrying, if you consistently end up with the same number being retried each time it probably indicates those items cannot be migrated for some reason. Exit out of the retry flow by pressing "n" and then check the errors on the items that failed to migrate.

Example cache file:

```json
{
"FqKGC9CCVThn857VAyZtZQq5L31njnbeUTe1JoCsCX8J": {
"error": "Migration failed with error: RPC response error -32002: Transaction simulation failed: Error processing Instruction 0: custom program error: 0x39 [5 log messages]"
},
"H7xrCZwA7oqsFeRcPsP6EEYHCxqq7atUBuuQAursXvWF": {
"error": "Migration failed with error: RPC response error -32002: Transaction simulation failed: Error processing Instruction 0: custom program error: 0x39 [5 log messages]"
}
}
```

In this case [our error is](https://github.com/samuelvanderwaal/wtf-is):

```
0x39:
Token Metadata | IncorrectOwner: Incorrect account owner
```

which means these items cannot be migrated over as they must have the same update authority as all items in the collection must have the same update authority as the Parent NFT.



Report bugs and questions to the [Metaboss Discord](https://discord.gg/2f7N25NJkg).

Binary file added docs-src/src/retry_flow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions docs/404.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title></title>
<title>Page not found - Metaboss</title>
<base href="/">


Expand Down Expand Up @@ -82,7 +82,7 @@

<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox">
<ol class="chapter"><li class="chapter-item expanded "><a href="overview.html"><strong aria-hidden="true">1.</strong> Overview</a></li><li class="chapter-item expanded "><a href="quick_start.html"><strong aria-hidden="true">2.</strong> Quick Start</a></li><li class="chapter-item expanded "><a href="examples.html"><strong aria-hidden="true">3.</strong> Examples</a></li><li class="chapter-item expanded "><a href="global_options.html"><strong aria-hidden="true">4.</strong> Global Options</a></li><li class="chapter-item expanded "><a href="burn.html"><strong aria-hidden="true">5.</strong> Burn</a></li><li class="chapter-item expanded "><a href="decode.html"><strong aria-hidden="true">6.</strong> Decode</a></li><li class="chapter-item expanded "><a href="derive.html"><strong aria-hidden="true">7.</strong> Derive</a></li><li class="chapter-item expanded "><a href="mint.html"><strong aria-hidden="true">8.</strong> Mint</a></li><li class="chapter-item expanded "><a href="set.html"><strong aria-hidden="true">9.</strong> Set</a></li><li class="chapter-item expanded "><a href="sign.html"><strong aria-hidden="true">10.</strong> Sign</a></li><li class="chapter-item expanded "><a href="snapshot.html"><strong aria-hidden="true">11.</strong> Snapshot</a></li><li class="chapter-item expanded "><a href="update.html"><strong aria-hidden="true">12.</strong> Update</a></li><li class="chapter-item expanded "><a href="withdraw.html"><strong aria-hidden="true">13.</strong> Withdraw</a></li><li class="chapter-item expanded "><a href="contact.html"><strong aria-hidden="true">14.</strong> Contact</a></li></ol>
<ol class="chapter"><li class="chapter-item expanded "><a href="overview.html"><strong aria-hidden="true">1.</strong> Overview</a></li><li class="chapter-item expanded "><a href="quick_start.html"><strong aria-hidden="true">2.</strong> Quick Start</a></li><li class="chapter-item expanded "><a href="examples.html"><strong aria-hidden="true">3.</strong> Examples</a></li><li class="chapter-item expanded "><a href="global_options.html"><strong aria-hidden="true">4.</strong> Global Options</a></li><li class="chapter-item expanded "><a href="burn.html"><strong aria-hidden="true">5.</strong> Burn</a></li><li class="chapter-item expanded "><a href="collections.html"><strong aria-hidden="true">6.</strong> Collections</a></li><li class="chapter-item expanded "><a href="decode.html"><strong aria-hidden="true">7.</strong> Decode</a></li><li class="chapter-item expanded "><a href="derive.html"><strong aria-hidden="true">8.</strong> Derive</a></li><li class="chapter-item expanded "><a href="mint.html"><strong aria-hidden="true">9.</strong> Mint</a></li><li class="chapter-item expanded "><a href="set.html"><strong aria-hidden="true">10.</strong> Set</a></li><li class="chapter-item expanded "><a href="sign.html"><strong aria-hidden="true">11.</strong> Sign</a></li><li class="chapter-item expanded "><a href="snapshot.html"><strong aria-hidden="true">12.</strong> Snapshot</a></li><li class="chapter-item expanded "><a href="update.html"><strong aria-hidden="true">13.</strong> Update</a></li><li class="chapter-item expanded "><a href="withdraw.html"><strong aria-hidden="true">14.</strong> Withdraw</a></li><li class="chapter-item expanded "><a href="contact.html"><strong aria-hidden="true">15.</strong> Contact</a></li></ol>
</div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav>
Expand Down
6 changes: 3 additions & 3 deletions docs/burn.html
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@

<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox">
<ol class="chapter"><li class="chapter-item expanded "><a href="overview.html"><strong aria-hidden="true">1.</strong> Overview</a></li><li class="chapter-item expanded "><a href="quick_start.html"><strong aria-hidden="true">2.</strong> Quick Start</a></li><li class="chapter-item expanded "><a href="examples.html"><strong aria-hidden="true">3.</strong> Examples</a></li><li class="chapter-item expanded "><a href="global_options.html"><strong aria-hidden="true">4.</strong> Global Options</a></li><li class="chapter-item expanded "><a href="burn.html" class="active"><strong aria-hidden="true">5.</strong> Burn</a></li><li class="chapter-item expanded "><a href="decode.html"><strong aria-hidden="true">6.</strong> Decode</a></li><li class="chapter-item expanded "><a href="derive.html"><strong aria-hidden="true">7.</strong> Derive</a></li><li class="chapter-item expanded "><a href="mint.html"><strong aria-hidden="true">8.</strong> Mint</a></li><li class="chapter-item expanded "><a href="set.html"><strong aria-hidden="true">9.</strong> Set</a></li><li class="chapter-item expanded "><a href="sign.html"><strong aria-hidden="true">10.</strong> Sign</a></li><li class="chapter-item expanded "><a href="snapshot.html"><strong aria-hidden="true">11.</strong> Snapshot</a></li><li class="chapter-item expanded "><a href="update.html"><strong aria-hidden="true">12.</strong> Update</a></li><li class="chapter-item expanded "><a href="withdraw.html"><strong aria-hidden="true">13.</strong> Withdraw</a></li><li class="chapter-item expanded "><a href="contact.html"><strong aria-hidden="true">14.</strong> Contact</a></li></ol>
<ol class="chapter"><li class="chapter-item expanded "><a href="overview.html"><strong aria-hidden="true">1.</strong> Overview</a></li><li class="chapter-item expanded "><a href="quick_start.html"><strong aria-hidden="true">2.</strong> Quick Start</a></li><li class="chapter-item expanded "><a href="examples.html"><strong aria-hidden="true">3.</strong> Examples</a></li><li class="chapter-item expanded "><a href="global_options.html"><strong aria-hidden="true">4.</strong> Global Options</a></li><li class="chapter-item expanded "><a href="burn.html" class="active"><strong aria-hidden="true">5.</strong> Burn</a></li><li class="chapter-item expanded "><a href="collections.html"><strong aria-hidden="true">6.</strong> Collections</a></li><li class="chapter-item expanded "><a href="decode.html"><strong aria-hidden="true">7.</strong> Decode</a></li><li class="chapter-item expanded "><a href="derive.html"><strong aria-hidden="true">8.</strong> Derive</a></li><li class="chapter-item expanded "><a href="mint.html"><strong aria-hidden="true">9.</strong> Mint</a></li><li class="chapter-item expanded "><a href="set.html"><strong aria-hidden="true">10.</strong> Set</a></li><li class="chapter-item expanded "><a href="sign.html"><strong aria-hidden="true">11.</strong> Sign</a></li><li class="chapter-item expanded "><a href="snapshot.html"><strong aria-hidden="true">12.</strong> Snapshot</a></li><li class="chapter-item expanded "><a href="update.html"><strong aria-hidden="true">13.</strong> Update</a></li><li class="chapter-item expanded "><a href="withdraw.html"><strong aria-hidden="true">14.</strong> Withdraw</a></li><li class="chapter-item expanded "><a href="contact.html"><strong aria-hidden="true">15.</strong> Contact</a></li></ol>
</div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav>
Expand Down Expand Up @@ -157,7 +157,7 @@ <h4 id="usage"><a class="header" href="#usage">Usage</a></h4>
<i class="fa fa-angle-left"></i>
</a>

<a rel="next" href="decode.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next" href="collections.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>

Expand All @@ -171,7 +171,7 @@ <h4 id="usage"><a class="header" href="#usage">Usage</a></h4>
<i class="fa fa-angle-left"></i>
</a>

<a rel="next" href="decode.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next" href="collections.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
Expand Down
Loading

0 comments on commit c64aeeb

Please sign in to comment.