ERC721PresetMinterPauserAutoId metadata not recognized by open seas

There was a post similar to this, but it didn't have a solution, so I'm asking again...

I started with the simple example code, and was able to get that to work, but the same process with my own code doesn't work. I've tried many iterations, and I hope there's some help here!

2_deploy.js (note the original example code is commented out)

// migrations/2_deploy.js
// SPDX-License-Identifier: MIT
const ERC721PresetMinterPauserAutoId = artifacts.require("ERC721PresetMinterPauserAutoId");

module.exports = function(deployer) {
   deployer.deploy(ERC721PresetMinterPauserAutoId, "PT and the Cruisers 8","Logo", "");


The link to the token metadata is "" and will return the same thing for any nftid, and the php has header('Content-Type: application/json;'); It will return:

[ { "id": 0, "name":"PT and the Cruisers Logo", "description":"Classic Rock Dance Band", "external_url":"....","image":"" }]

I then do the following:

truffle console --network rinkeby
truffle(rinkeby)>deploy --reset
truffle(rinkeby)>nft = await ERC721PresetMinterPauserAutoId.deployed()

all of which seem to work fine. However, openseas hates it,

when I look at the source of the openseas page, I see the link to my token file. (..../list.php?nftid=0") so it has gotten it, but when it reads it I guess there's something wrong with it.
I've tried adding { "tokens":"[ ... didn't work.
I've tried removing the [ so it just starts with {"id": 0, .. didn't work.
I've tried removing the id field, didn't work...

There's something basic wrong here that I'm not getting.... help!

thanks in advance,

NEVER MIND... I got some debugging done with Rarible and found the magic format that works.

1 Like

Hi @dchura7734! Please share your learnings with the community!

I'm happy to do so - I just assume everyone else knows more than I do...
Here's what I've found, using Rarible and OpenSeas on Rinkeby for testing:

  1. The metadata URL in the constructor for ERC721PresetMinterPauserAutoId is accessed by Rarible/OpenSeas, and your implementation would return the following:
  • A single JSON object starting with { and ending with }. (not an array of objects)
  • An HTTP header with Content-Type: application/json; which in php is achieved with this:
    header('Content-Type: application/json;');
    Is this only way it can work? I'm not sure, but this does work.
  1. Rarible and OpenSeas save the result of hitting that metadata URL, so it will only re-load if you explicitly click on a "refresh metadata" option at their site. It is actually interesting (to me) that the refresh exists at all, but was the key element for me in debugging this... Note that Rarible refresh is synchronous and OpenSeas is asynchronous, so Rarible is easier to use. BTW, the same is true of the asset itself (usually an image), so you can expect Rarible an OpenSeas to have N copies of your original.

  2. Note my metadata URL ends in ".......?nftid=" . The token id created by ERC721PresetMinterPauserAutoId (that's the auto part!) is appended to this URL before it is used, so you can distinguish between different tokens, like "....?nftid=99" I use php, and a .php URL works fine.

  3. And... this is the most useful thing I learned. You can deploy your contract (it is called ERC721PresetMinterPauserAutoId in the example code, see 2_deploy.js) only once, and then mint as many tokens as you want without deploying again!

At this point, the ERC721PresetMinterPauserAutoId was not useful anymore to me. The autoid function is convienent, but I created my own contract (from the AutoId code) that allows explicit assignment of tokenIds. the AutoId contract has
and my contract adds:
mintWithTokenID("0x......", 774). which has explicit tokenID 774

At that point I could do this with my contract:

truffle(rinkeby)>deploy   [uses the same 2_deploy.js, but with my complied contract]
truffle(rinkeby)>nft = await ERC721enclayveItem.deployed()
truffle(rinkeby)>await nft.mintWithTokenID("0x....", 77)
truffle(rinkeby)>await nft.mintWithTokenID("0x....", 78)
truffle(rinkeby)>await nft.mintWithTokenID("0x....", 79)

Which puts three different assets into Rarible and OpenSeas. And... at those systems, all of these assets appear under the same "Collection" in Rarbile/OpenSeas. The "Collection" name comes from the "name" field used in the constructor for the contract in 2_deploy.js

To me, managing my own Token IDs is preferred because I can then assign them in advance (and I can make them distinct easily), so my server-side database of assets can have an nftid field I control. The metadata URL uses the nftid=XXXX, which is a simple lookup in our asset database and returns proper JSON reference to the asset itself.

It's also a little more secure, since the IDs are big long numbers and someone who spams our web site with random IDs (in the metadata URL. "https://.........?nftid=X" where they try every X won't likely find anything. I think the autoid design starts with 0 and counts up, which is pretty exposed. This can be eased with replacing the counter in AutoID contract with a random number, but you still don't know the tokenIDs in advance which (to me) makes everything harder to code in the overall system.

That is, the example code wants you to do this:

truffle(rinkeby)>nft = await ERC721PresetMinterPauserAutoId.deployed()

And I've now minted 3 assets, but I don't know what their tokenIDs are, and then of course I don't know how to look them up in my server's database to generate the actual assert URL, etc. etc, I think you can see where I'm going with this. This minting sequence just doesn't work unless you have a-priori information about the tokenIds (it's a chicken-and-egg problem....)

1 Like