In the newest version of Metaplex Core we’re excited to introduce another External Plugin for all Core assets. Today, we’ll dive into the details of the new AppData Plugin!
This article covers everything you need to know about the AppData Plugin, providing context on External Plugins and Core.
We’ll explore:
Possible use cases
How the plugin works
Code example in TypeScript
PS: This is for non-technical people too! So stay until the end to learn everything you need to know to implement it in your project. And if you’re still having problems, reach out to the community developers on Discord!
Setting the Stage: Understanding Core External Plugins
Before diving deep into the AppData Plugin, it’s important to understand the context of how this revolutionary new standard works.
Metaplex Core
Metaplex Core (“Core”) is a new standard created specifically for digital assets. By moving away from the standard SPL-Token Program, Metaplex eliminated the complexity and technical debt of the previous standard (Token Metadata), providing a clean and simple interface for digital assets.
This new implementation uses a single account design, significantly reducing minting costs and optimizing network load by streamlining instruction processes. Additionally, it features a flexible plugin system that allows developers to modify the behavior and functionality of assets.
Here are the biggest differences and improvements:
Unprecedented Cost Efficiency: Metaplex Core offers the lowest minting costs compared to available alternatives. For instance, an NFT that would cost 0.022 SOL with Token Metadata or 0.0046 SOL with Token Extensions can be minted with Core for just 0.0029 SOL.
Low Compute: Core operations have a small Compute Unit footprint. This allows more transactions to be included in one block. Instead of 205,000 CU for minting, Core requires just 17,000 CU.
Single Account Design: Unlike relying on a fungible Token Standard like SPL Token or Token Extensions (aka Token22), Core focuses on the needs of an NFT standard. This allows Core to use a single account that also tracks the owner.
External Plugin
A plugin is like an on-chain app for your NFT that can either store data or provide additional functionality to the asset.
External Plugins are part of the Authority-managed Plugin family, meaning only the authority of the Core Asset or Core Collection can add and update the plugin on the asset.
Note: If an Authority Managed Plugin is added to an asset/collection without an authority argument present, the plugin will default to the authority type of update authority.
There are two key components in the external plugin family:
Adapter: Allows data and validations to be passed from an External Plugin.
External Plugin: Provides the data and validation for the Adapter.
Typically, each External Adapter can assign lifecycle checks to Lifecycle Events, influencing the behavior of these events and the data is not stored on the asset itself.
The AppData Plugin is unusual because the data is saved directly on the asset and no lifecycle checks are available for it. But it’s still considered an External Plugin because it’s managed by an external source of trust appointed by the Authority.
Note: The Data Authority of an External Plugin is the only entity allowed to write to the External Plugin’s data section.
What is the AppData Plugin and Why Should You Care About It?
Now that we have a better understanding of how core assets and external plugins work, let’s dive into the new AppData Plugin.
What is the AppData Plugin?
The AppData Plugin allows asset/collection authorities to save arbitrary data that can be written and changed by the data_authority
, an external source of trust and can be assigned to anyone the asset/collection authority decides to.
With the AppData Plugin, collection/asset authorities can delegate the task of adding data to their assets to trusted third parties.
There are two types of AppData Plugin:
AppData is reserved for individual assets;
LinkedAppData is used for collections but both achieve the same functionality
Note: if the collection has a LinkedAppData plugin, the individual assets inherit that data too!
How Does It Work?
The AppData Plugin has two main fields:
Authority: Who has the ability to change the data.
Data: The actual data being stored.
The AppData Struct
The AppData struct is defined as follows:
pub struct AppData {
pub data_authority: Authority,
pub schema: ExternalPluginAdapterSchema,
}
The data_authority
is of Authority type:
pub enum Authority {
None,
Owner,
UpdateAuthority,
Address { address: Pubkey },
}
The schema
is defined as ExternalPluginAdapterSchema
:
pub enum ExternalPluginAdapterSchema {
#[default]
Binary,
Json,
MsgPack,
}
So for the AppData plugin we can set an authority that can be the owner of the asset, the updateAuthority of the asset or an external address. And the data type that we can put inside are Binary, Json or MsgPack.
Note: The data_authority
cannot be updated or revoke once initialized in the plugin, if necessary, the entire plugin can be removed by the asset/collection authority, providing a way to reset that field.
Examples of How Protocols Could Integrate the AppData Plugin into Their NFTs
Onchain Ticketing
Consider a system where the authority to issue tickets is distinct from the authority to validate their use. For instance, a platform like TicketMaster issues the tickets, while each individual venue manages ticket validation.
Using AppData, the ticketing platform can issue digital assets as tickets, retaining full control over their issuance to ensure everything is in order. Initially, the data schema will include a status field marked as Unused with the data_authority
set to the venue organizer, allowing them to update the ticket status. Upon entry, the venue scans the ticket NFT and updates the status field in the AppData schema to Used, possibly adding a timestamp as well so we can have a record for it.
Benefits:
Ensures that ticket issuance and validation are securely and independently managed.
Provides a transparent and immutable record of ticket status, preventing fraud and double-use.
Luxury Real-World Asset (RWA) Authentication and Storage
Consider a startup that tokenizes luxury real-world assets (such as watches) and needs to ensure regulatory compliance and authenticity.
Using AppData, the startup can issue digital assets representing each luxury asset, integrating the AppData Plugin to store a schema with authentication details and storage locations. The data_authority
is given to a third-party firm that verifies the authenticity and records its findings directly into the AppData schema. Whenever the asset is moved, the firm updates the storage location in the data schema, ensuring a current and accurate record.
Benefits:
Provides a trusted and verifiable record of the asset’s authenticity and storage history.
Enhances regulatory compliance and ensures the legality of the tokenized assets.
Intellectual Property and Patent Tracking
Consider digital assets representing intellectual property (IP) and patents, where the owner is entitled to royalties, and the status of filings and grants needs to be updated frequently.
Using AppData, the IP owner issues digital assets representing their patents or IP rights, defining a schema to include fields for filing status, grant dates, and licensing agreements. The IP owner then assigns a patent office or a trusted IP management service as the data_authority
to update the schema with new filings, grant statuses, and any licensing agreements or changes, ensuring that the information is always current and accurate.
Benefits:
Provides a transparent and immutable record of IP status and ownership.
Ensures that all updates are managed by a trusted authority, enhancing the credibility and value of the NFTs.
Let’s get our hands dirty — Creating an NFT with the AppData Plugin
Now that you know all about AppData NFTs, let’s create an example using them!
Dependencies and Imports
The dependencies used are as follows:
import { generateSigner, createSignerFromKeypair, signerIdentity } from '@metaplex-foundation/umi'
import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
import { create, writeData, ExternalPluginAdapterSchema } from "@metaplex-foundation/mpl-core"
import { base58 } from '@metaplex-foundation/umi/serializers';
Umi Overview
In this example, we’ll use Umi to create all necessary instructions.
Umi is a modular framework for building and using JavaScript clients for Solana programs that provides a zero-dependency library and defines a set of core interfaces, enabling libraries to operate independently of specific implementations.
For more information, you can find an overview here.
The basic Umi setup for this example will look like this:
// Wallet generated as a uint8 array
import wallet from "../wallet.json";
const umi = createUmi("https://api.devnet.solana.com", "finalized")
let keypair = umi.eddsa.createKeypairFromSecretKey(new Uint8Array(wallet));
const myKeypairSigner = createSignerFromKeypair(umi, keypair);
umi.use(signerIdentity(myKeypairSigner));
This setup involves:
Establishing a connection with Devnet for our Umi provider
Setting up a keypair to be used as both the authority and payer
umi.use(signerIdentity(…))
Note: If you prefer to use a new keypair for this example, you can always use the generateSigner()
function to create one.
Creating an Asset and Adding the AppData Plugin
Before populating the AppData plugin with the data we want, we need to set it up and choose who will have the data_authority
over this plugin and define the data type.
For this example, I choose the address used to create the asset and save the data in binary form.
// Generate the Asset KeyPair
const asset = generateSigner(umi);
console.log("\nAsset Address: ", asset.publicKey.toString());
// Generate the Asset
const tx = await create(umi, {
name: 'My NFT',
uri: 'https://example.com/my-nft.json',
asset: asset,
plugins: [
{
type: "AppData",
dataAuthority: {type: "Address", address: myKeypairSigner.publicKey},
schema: ExternalPluginAdapterSchema.Binary,
}
]
}).sendAndConfirm(umi)
Adding Data to the AppData Plugin
Now that you’ve added the plugin, the dataAuthority can use the writeData instruction to write the “Hello World!” string in binary form using the Buffer.from()
function.
writeData(umi, {
asset: asset.publicKey,
key: {
type: "AppData",
dataAuthority: {type: "Address", address: myKeypairSigner.publicKey},
},
data: Buffer.from("Hello World!"),
}).sendAndConfirm(umi);
Aaaaand we’re done! Enjoy your first asset leveraging the new AppData Plugin!