Generalized Ownable Indexable Assets
Summary
This is a standard protocol to enables RPCs to track assets that programs to create, replace, update, and delete for users. Indexers will be able to interpret “owned” program data by executing a pre-determined simulated view function on the program.
Motivation
We want to support forking of commonly used protocols, so that big enterprises can have full control and maintainability over their contracts, while also retaining the ability to have their program’s data indexed & shown in wallets.
Centralized control of commonly used protocols leads to catastrophic failure scenarios when the trusted operator is compromised. Short term work-arounds in previous upheavals, e.g. the genesis of OpenBook, have failed to produce meaningful abstraction patterns on Solana. As developers on Solana begin to realize the risks of centralized protocols, they may want to fork even the SPL Token program.
However they will quickly run into issues getting adoption into marketplaces, dApps, and wallets. This is both a social and technical problem. We hope that this standard for indexing will solve the technical problem, and thus reduce the tension in the social problem of adoption.
Specification
Require the usage of CPI events. See sRFC #00013.
We propose that programs control ownable assets for wallets using the following 4 CRUD event structs.
The payload of these events is used to manage an Asset
which has an ID of type Pubkey
, and consists of an ordered array of Pubkey
s.
// Inform indexers that a new Asset Group was created for an authority
pub struct CrudCreate {
asset_id: Pubkey,
authority: Pubkey,
pubkeys: Vec<Pubkey>,
data: Vec<u8>
}
// Inform indexers to change both authority & pubkeys
pub struct CrudReplaceKeys {
asset_id: Pubkey,
authority: Pubkey,
pubkeys: Vec<Pubkey>
}
// Inform indexers to update the bytes for an asset group
pub struct CrudUpdateBytees {
asset_id: Pubkey,
owner: Pubkey
}
// Inform indexers to delete the asset
pub struct CrudDestroy {
asset_id: Pubkey
}
Indexers will store assets issued by programs, so that you will always be able to query /getAssetsForOwner { program_id, wallet }
and have it return a list of Asset { id: Pubkey, pubkeys: Vec<Pubkey>, data: Vec<u8>}
.
Optionally, indexers can ask the program for a human readable interpretation of the Asset
’s data by simulating view functions on the program that it belongs to. This is done by sending the getAssetData
anchor instruction with no arguments, and deserializing the return_value
as a JSON.
Programs that comply with this spec will have similar implementation as below:
#[program]
pub mod my_program {
...
pub fn get_asset_data(ctx: Context<GetAssetData>, data: Vec<u8>) -> Ok(()) {
let asset_id_account = &ctx.accounts.asset_id.to_account_info();
let asset_accounts = &ctx.remaining_accounts.to_vec();
// interpret asset data
let my_json_bytes = // serialize asset data here
set_return_data(my_json_bytes)
Ok(())
}
}
#[derive(Accounts)]
pub struct GetAssetData<'info> {
/// CHECK:
pub asset_id: AccountInfo<'info>,
/// CHECK:
pub authority: AccountInfo<'info>,
}
This will allow indexers to serve JSON data from each Asset
that the program has issued.
Implementation:
TBD