External Plugins
AppData Plugin
What is an AppData Plugin?
The AppData
external plugin stores and contains arbitrary data that can be written to by the dataAuthority
. Note this is different then the overall plugin authority stored in the ExternalRegistryRecord
as it cannot update/revoke authority or change other metadata for the plugin.
Think of AppData
as like a partition data area of an Asset that only a certain authority can change and write to.
This is useful for 3rd party sites/apps to store data needed to execute certain functionality within their product/app.
Works With
MPL Core Asset | ✅ |
MPL Core Collection* | ✅ |
* MPL Core Collections can also work with the LinkedAppData
Plugin.
What is a LinkedAppData Plugin?
The LinkedAppData
plugin is built for Collections. It allows you to add a single plugin adapter on the collection which will allow you to write to any Asset in the collection.
Arguments
Arg | Value |
---|---|
dataAuthority | PluginAuthority |
schema | ExternalPluginAdapterSchema |
dataAuthority
AttributeList
const dataAuthority = {
type: 'Address',
address: publicKey('11111111111111111111111111111111'),
}
schema
The schema determines the type of data that is being stored within the AppData
plugin. All schemas will be indexed by DAS.
Arg | DAS Supported | Stored as |
---|---|---|
Binary (Raw Data) | ✅ | base64 |
Json | ✅ | json |
MsgPack | ✅ | json |
When indexing the data if there was an error reading the JSON
or MsgPack
schema then it will be saved as binary.
Writing data to the `AppData` plugin
import { ExternalPluginAdapterSchema } from '@metaplex-foundation/mpl-core'
// Chose from Binary, Json or MsgPack
const schema = ExternalPluginAdapterSchema.Json
Adding the AppData Plugin to an Asset
Adding a Attribute Plugin to an MPL Core Asset
import { publicKey } from '@metaplex-foundation/umi'
import { addPlugin, ExternalPluginAdapterSchema } from '@metaplex-foundation/mpl-core'
const assetSigner = generateSigner(umi);
const dataAuthority = publicKey('11111111111111111111111111111111')
await create(umi, {
asset: asset.publicKey,
name: "My Asset",
uri: "https://example.com/my-assets.json"
plugins: [
{
type: 'AppData',
dataAuthority,
schema: ExternalPluginAdapterSchema.Json,
},
],
}).sendAndConfirm(umi)
// Alternatively you could add the plugin to an existing Asset
await addPlugin(umi, {
asset,
plugin: {
type: 'AppData',
dataAuthority,
schema: ExternalPluginAdapterSchema.Json,
},
})
Writing Data to the AppData Plugin
Only the dataAuthority address can write data to the AppData
plugin.
To write data to the AppData
plugin we will use a writeData()
helper which takes the following args.
Arg | Value |
---|---|
key | { type: string, dataAuthority: publicKey} |
authority | signer |
data | data in the format you wish to store |
asset | publicKey |
Serializing JSON
Serializing JSON
const json = {
timeStamp: Date.now(),
message: 'Hello, World!',
}
const data = new TextEncoder().encode(JSON.stringify(json))
Serializing MsgPack
Serializing MsgPack
// This implementation uses `msgpack-lite` for serialization
const json = {
timeStamp: Date.now(),
message: 'Hello, World!',
}
const data = msgpack.encode(json)
Serializing Binary
As binary can store arbitrary data it's up to you to decide on how you are going to serialize and deserialize the data.
Serializing Binary
// The below example is just creating bytes that are considered `true` or `false`.
const data = new Uint8Array([1, 0, 0, 1, 0])
Writing Data
Adding a Attribute Plugin to an MPL Core Asset
await writeData(umi, {
key: {
type: 'AppData',
dataAuthority,
},
authority: dataAuthoritySigner,
data: data,
asset: asset.publicKey,
}).sendAndConfirm(umi)
Reading Data from the AppData Plugin
Data can be both read on chain programs and external sources pulling account data.
Fetch the Raw Data
The first step to deserializing the data stored in an AppData
plugin is to fetch the raw data and check the schema field which dictates the format in which the data is stored before serialization.
Fetching `AppData` Raw Data
const assetId = publicKey('11111111111111111111111111111111')
const dataAuthority = publicKey('33333333333333333333333333333333')
const asset = await fetchAsset(umi, assetId)
let appDataPlugin = asset.appDatas?.filter(
(appData) => (appData.authority.address = dataAuthority)
)
let data
let schema
// Check if `AppData` plugin with the given authority exists
if (appDataPlugin && appDataPlugin.length > 0) {
// Save plugin data to `data`
data = appDataPlugin[0].data
// Save plugin schema to `schema`
schema = appDataPlugin[0].schema
}
Deserialization
Now that you have the data you'll need to deserialize the data depending on the schema you chose to write the data with to the AppData
plugins.
Deserialize JSON Schema
Deserializing JSON
// Due to the JS SDK, the deserialization for the MsgPack schema is automatic and deserialized
// data can be accessed at the RAW location example above.
Deserialize MsgPack Schema
Deserializing MsgPack
// Due to the JS SDK, the deserialization for the MsgPack schema is automatic and deserialized
// data can be accessed at the RAW location example above.
Deserialize Binary Schema
Because the Binary schema is arbitrary data then deserialization will be dependent on the serialization you used.
Deserializing Binary
// As the binary data is arbitrary you will need to include your own deserializer to
// parse the data into a usable format your app/website will understand.