Looking for the upgradable avatars? Meta Blocks Avatars are now called 3moji.Learn more
📥

11. How deposits work

As we have seen on how Metablocks protocol works in the previous `Architecture` chapter. And After creating a `Universe`, the next step is to deposit an NFT to the universe.

You can think of every deposited NFT as a component of your main character. All the deposited NFTs together constitute the `meta NFT`. The `meta NFT` combines the metadata of all component NFTs.

(For more details - please go through this - @kyraa/metablocks )

How is an NFT stored in a universe?

Below section demonstrates the deposition of component-NFT in depth.

Depositing an NFT into Metablocks can be classified into a 3 step process.

  1. Create Metablocks Authority and create Meta-NFT
  2. Create Receipt NFT
  3. Deposit NFT into Metablocks Vault and transfer Receipt NFT to the User

1. Create Metablocks Authority and create Meta-NFT

1.1 Creation of MetaBlocks Authority

The Metablocks Authority is PDA authority owned by the Meta-Blocks program. This PDA is useful for performaing various actions on metaNFT(more about this in the following section) of the user.

What does it do anyway ? -

It acts as an escrow authority where Meta-NFT could be burnt, frozen or transferred based on the NFTs deposited by the User

The PDA is generated by the following code.

const MetaBlocksAuthorityPDA = async (
  universeKey: PublicKey,
  depositorKey: PublicKey
) => {
  return await PublicKey.findProgramAddress(
    [
      Buffer.from(utils.bytes.utf8.encode('MetaBlocksAuthority')),
      universeKey.toBuffer(),
      depositorKey.toBuffer(),
    ],
    programIds.META_BLOCKS_PROGRAM_ID
  );
};

As we can see that PDA is generated based on universe and depositor public addresses.

1.2 Initialization of Meta-NFT

Meta-NFT mint is generated using a Meta-NFT program. It serves the purpose of generating Meta-NFT and keeping track of NFTs deposited by the user.

The mint is again is a program owned PDA. This could be generated using like -

const MetaNftMintAddressPDA = async (
  universeKey: PublicKey,
  depositorKey: PublicKey
) => {
  return await PublicKey.findProgramAddress(
    [
      Buffer.from(utils.bytes.utf8.encode('MetaNftMint')),
      universeKey.toBuffer(),
      depositorKey.toBuffer(),
    ],
    programIds.META_NFT_PROGRAM_ID
  );
};

Even the Depsoitor Address is stored in the program state. This is done in this way so that when we Create the Meta-NFT , the one who initializes the Meta-NFT , will always receives the Meta-NFT. The state of the program is a PDA generated address as below

const MetaNftAddressPDA = async (
  depositorKey: PublicKey,
  universeKey: PublicKey
) => {
  return await PublicKey.findProgramAddress(
    [
      Buffer.from(utils.bytes.utf8.encode('MetaNft')),
      universeKey.toBuffer(),
      depositorKey.toBuffer(),
    ],
    programIds.META_NFT_PROGRAM_ID
  );
};

1.3 Creation of Meta-NFT

Once we have the mint address of Meta-NFT, we can create the Meta-NFT using token-metadata of Metaplex. A CPI call is made to token-metadata to create the standard Meta-NFT. After creation it is transferred to the Associated Address of the user. The associated address can be generated by

const AssociatedAddressPDA = async (
  depositorKey: PublicKey,
  mintKey: PublicKey
) => {
  const tokenProgramID = programIds.TOKEN_PROGRAM_ID;

  return await PublicKey.findProgramAddress(
    [
      depositorKey.toBuffer(),
      tokenProgramID.toBuffer(),
      mintKey.toBuffer(),
    ],
    programIds.ASSOCIATED_TOKEN_PROGRAM_ID
  );
};

The metadata for generating token-metadata is passed as arguments while creating Meta-NFT for the user. The arguments required while generating Meta-NFT is name of the NFT, uri .

2. Create Receipt NFT

The receipt-NFT is the proof that user has deposited into the Meta-Blocks program. The receipt NFT mint is generated separately before depositing into the MetaBlocks vault.

2.1 Initialize Receipt Mint address

Like described in the previous section about mint generation for meta-NFT, even receipt mint is generated is the same way with slight modification in the PDA generation for receipt-mint.

const ReceiptMintAddressPDA = async (
  universeKey: PublicKey,
  depositorKey: PublicKey,
  nftMintAddress: PublicKey
) => {
  return await PublicKey.findProgramAddress(
    [
      Buffer.from(utils.bytes.utf8.encode('ReceiptNftMint')),
      universeKey.toBuffer(),
      depositorKey.toBuffer(),
      nftMintAddress.toBuffer(),
    ],
    programIds.META_BLOCKS_PROGRAM_ID
  );
};

3. Deposit NFT into Metablocks Vault and transfer Receipt NFT to the User

Once the receipt-mint is created, a state called wrapped-user-nft stores all the necessary values for depositing and withdrawing the NFTs from the program.

The wrapped-user-nft is a PDA generated address.

const WrappedUserNftAddressPDA = async (
  depositorKey: PublicKey,
  receiptMintKey: PublicKey
) => {
  return await PublicKey.findProgramAddress(
    [
      Buffer.from(utils.bytes.utf8.encode('WrappedUserNft')),
      depositorKey.toBuffer(),
      receiptMintKey.toBuffer(),
    ],
    programIds.META_BLOCKS_PROGRAM_ID
  );
};

Later receipt mint NFT is first transfered to vault until user's nft is stored into the vault. The Vault address is again a PDA generated address.

Vault address

const VaultAddressPDA = async (
  universeKey: PublicKey,
  depositorKey: PublicKey,
  nftMintAddress: PublicKey
) => {
  return await PublicKey.findProgramAddress(
    [
      Buffer.from(utils.bytes.utf8.encode('VaultMetaBlocks')),
      universeKey.toBuffer(),
      depositorKey.toBuffer(),
      nftMintAddress.toBuffer(),
    ],
    programIds.META_BLOCKS_PROGRAM_ID
  );
};

Again, this PDA is used to generate an associated address to store the user's NFT.

Vault ATA

const VaultAssociatedPDA = async (
  tokenRecipientKey: PublicKey,
  nftMintKey: PublicKey
) => {
  const tokenProgramID = programIds.TOKEN_PROGRAM_ID;

  return await PublicKey.findProgramAddress(
    [
      vaultKey.toBuffer(),
      tokenProgramID.toBuffer(),
      nftMintKey.toBuffer(),
    ],
    programIds.ASSOCIATED_TOKEN_PROGRAM_ID
  );
};

Now, that we have everything in place, CPI call is made to token-metadata to generate the receipt-NFT and is minted to Vault associated address. Then user's NFT is transfered to Vault and vice versa, the Receipt mint is transfered back to the User's Associated address.

This receipt NFT has the same metadata as the deposited NFT, but it cannot be transferred by the user. This receipt can only be used to get the component(deposited) NFT back from the program.

Meta Blocks Logo
© 2021
Meta Blocks
This open-source site was built with React Static.
Hosting and deployment courtesy of Cloudflare.
Solana LogoPowered by Solana