1. Structuring your smart contract

Leveraging the ERC721 standard to make your items instantly tradeable on OpenSea

​Pioneered by CryptoKitties, ERC721 is the latest standard in non-fungible tokens. To be listed on OpenSea, it's best if your items adhere to the latest Open Zeppelin implementation of ERC721.

*If you're developing an ERC1155ERC1155 - a novel token standard built on top of ERC721 that aims to take the best from previous standards to introduce semi-fungibility to NFTs. With ERC1155, IDs represent not single assets but classes of assets. For example, an ID might represent “swords”, and a wallet could own 1,000 of these swords contract, please check out our ERC1155 Tutorial.

OpenSea Creature Sample Contract

We've created a very simple starter repository to get you started. The full code for the sample can be found on Github.

The sample code is a collectible called OpenSea Creatures. OpenSea Creatures are pretty basic: they each have a unique look, traits, and attributes. While one day we may add more of a game around these creatures, for the purpose of this example, the main thing you can do with a creature is own it. You can check out all the OpenSea creatures on the RinkebyRinkeby - Rinkeby is an Ethereum testnet (or test network). Testnets are typically used by developers to run "tests" for their application or software. environment for OpenSea here.

Creature ERC721 contract

pragma solidity ^0.5.0;

import "./TradeableERC721Token.sol";
import "openzeppelin-solidity/contracts/ownership/Ownable.sol";

 * @title Creature
 * Creature - a contract for my non-fungible creatures.
contract Creature is TradeableERC721Token {
  constructor(address _proxyRegistryAddress) TradeableERC721Token("Creature", "OSC", _proxyRegistryAddress) public {  }

  function baseTokenURI() public view returns (string memory) {
    return "https://opensea-creatures-api.herokuapp.com/api/creature/";

As you can see, the contract itself is pretty simple. It just inherits from TradeableERC721Token, which in turn inherits from the OpenZeppelin ERC721 contracts (which implement all of the necessary ERC721 methods). You'll probably have more logic in your game, but the important piece for OpenSea is the tokenURI method, which allows us to map the tokenId's in the Creature contract to some metadata off-chain about the contract. We'll learn more about this in the next section.

OpenSea Whitelisting (optional)

Additionally, the ERC721Tradable and ERC1155Tradable contracts whitelist the proxy accounts of OpenSea users so that they are automatically able to trade any item on OpenSea (without having to pay gas for an additional approval). On OpenSea, each user has a "proxy" account that they control, and is ultimately called by the marketplace contracts to trade their items.

Note that this addition does not mean that OpenSea itself has access to the items, simply that the users can list them more easily if they wish to do so. It's entirely optional, but results in significantly less user friction. You can find this code in the overridden isApprovedForAll method, along with the factory mint methods.

Next we'll learn about how to structure that metadata so it can be picked up by OpenSea.

Using Ownable

For developers to set up contracts on OpenSea automatically.

Deploying your contract

To deploy the Creature contract, simply check out the repo, get a free Alchemy API key, and deploy with Truffle:

yarn install
export ALCHEMY_KEY="<your_alchemy_project_id>"
export MNEMONIC="<metamask>"
export NETWORK="rinkeby"
yarn truffle deploy --network rinkeby

If you're using Infura API already, you can also use the INFURA_KEY environment variable instead of ALCHEMY_KEY.


Quick tip

You only need to run the export lines above once in your shell session. We recommend that you put those lines into a .env file, apply it once using . .env, and avoid checking it in when committing your code. There's a sample .env file here.

Note that in order to deploy with Truffle and Infura, you'll need a "seed phrase" from a MetaMask account that is funded with Ether. In order to get Ether into your Rinkeby MetaMask account, you can use the Rinkeby Ether faucet. You'll need to post a message to one of your social profiles and paste the link to your post in the test faucet. In order to obtain your "seed phrase" from Metamask click "settings" and click "reveal seed words". Make sure you don't share your seed phrase for any accounts containing Mainnet tokens!

Minting your tokens

Next, we'll want to mint new assets to our newly-deployed ERC721 contracts! We'll mint these assets into an account that we control so that we can test the OpenSea auction flow for our items.

After deploying to the Rinkeby network, there will be a contract on Rinkeby that will be viewable on Rinkeby Etherscan. You can find the address of the deployed contract in the output of the deployment command and find it on Etherscan by hitting the URL: https://rinkeby.etherscan.io/address/<contract_address>.

For example, here is a recently deployed contract. You should set this contract address and the address of your MetaMask account as environment variables when running the minting script:

export OWNER_ADDRESS="<my_address>"
export NFT_CONTRACT_ADDRESS="<deployed_contract_address>"
node scripts/mint.js

What's next?

At this point, we've deployed our first smart contract on the Rinkeby network and minted some new OpenSea creatures on our contract. You should be able to visit rinkeby.opensea.io and view your new creatures as NFTs inside your wallet! More on that in section 3.

The default metadata for the creatures is provided by https://opensea-creatures-api.herokuapp.com/api/creature/{token_id}, which is set here. Next, you'll need create your custom metadata API.

What’s Next

Let's learn more about the metadata associated with each CryptoPuff.