Le Programme Token2022
Le Programme Token2022, également connu sous le nom de Token Extensions (Extension de Jetons), est un ensembles plus large de fonctionnalités fournies par le Programme de Jetons.
Le Programme Legacy Token répond à la plupart des besoins en matière de jetons fongibles et non fongibles grâce à un ensemble simple d'interfaces et de structures agnostiques. Cependant, il manque des fonctionnalités et des implémentations plus avancées qui aideraient les développeurs à créer des comportements personnalisés avec une interface commune, rendant ainsi le développement plus rapide et plus sûr.
C'est précisément pour cette raison qu'un nouveau Programme de Jetons appelé Token2022
a été créé et doté d'un nouvel ensemble de fonctionnalités appelées Token Extensions
. Ces extensions fournissent des comportements spécifiques et personnalisables qui peuvent être associés soit au Token Account
soit au Mint Account
.
Comptes de Mint et Comptes de Jetons
Dans la section précédente, nous avons évoqué le fait que la principale différence entre les programmes Tokenkeg
et Token2022
réside dans les Token Extensions.
Pour être applicables, ces extensions doivent être directement intégrées aux comptes de Mint
et Token
car c'est le seul moyen de garantir que l'ensemble de règles soit appliqué tout en fonctionnant directement au niveau du programme de jetons.
Pour cette raison, examinons les principales différences entre le programme de jetons "classique" et le nouveau programme de jetons sur ces comptes.
Comptes de Jetons "classique"
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Mint {
/// Optional authority used to mint new tokens. The mint authority may only
/// be provided during mint creation. If no mint authority is present
/// then the mint has a fixed supply and no further tokens may be
/// minted.
pub mint_authority: COption<Pubkey>,
/// Total supply of tokens.
pub supply: u64,
/// Number of base 10 digits to the right of the decimal place.
pub decimals: u8,
/// Is `true` if this structure has been initialized
pub is_initialized: bool,
/// Optional authority to freeze token accounts.
pub freeze_authority: COption<Pubkey>,
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Account {
/// The mint associated with this account
pub mint: Pubkey,
/// The owner of this account.
pub owner: Pubkey,
/// The amount of tokens this account holds.
pub amount: u64,
/// If `delegate` is `Some` then `delegated_amount` represents
/// the amount authorized by the delegate
pub delegate: COption<Pubkey>,
/// The account's state
pub state: AccountState,
/// If `is_native.is_some`, this is a native token, and the value logs the
/// rent-exempt reserve. An Account is required to be rent-exempt, so
/// the value is used by the Processor to ensure that wrapped SOL
/// accounts do not drop below this threshold.
pub is_native: COption<u64>,
/// The amount delegated
pub delegated_amount: u64,
/// Optional authority to close the account.
pub close_authority: COption<Pubkey>,
}
Comme vous pouvez le constater, il n'y a pas de discriminateur pour ces comptes. En effet, les champs ont tous une longueur fixe et la différence d'espace est suffisante pour distinguer ces différents types de comptes en comparant simplement leurs différentes longueurs.
Le problème avec le Programme d'Extension de Jetons est que toutes les données supplémentaires nécessaires à l'extension sont ajoutées à la fin des comptes Mint
et Token
.
Cela signifie que la distinction basée sur la longueur serait insuffisante car nous pourrions avoir un Mint
avec 3 ou 4 extensions qui dépasseraient la longueur du compte de Token
. Pour cette raison, lorsque des comptes de Mint
et de Token
ont des extensions, un discriminateur leur est ajouté comme ceci :
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Mint {
/// Legacy Token Program data
/// ...
/// Padding (83 empty bytes)
pub padding: [u8; 83]
/// Discriminator (1)
pub discriminator: u8
/// Extensions data
/// ...
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Account {
/// Legacy Token Program data
/// ...
/// Discriminator (2)
pub discriminator: u8
/// Extensions data
/// ...
}
Pour conserver la structure existante, le discriminateur ne se trouve pas au premier octet comme d'habitude mais à l'octet 166
.
En effet, la longueur du compte de Token
est de 165 octets ce qui signifie que le discriminateur est ajouté après la longueur de base. Pour le compte de Mint
cela signifie que nous avons dû ajouter 83 octets de remplissage (padding) afin de garantir que les deux comptes aient la même longueur de base.
Pour distinguer les deux comptes, il suffit donc de vérifier le 166e octet (data[165] si vous comptez à partir de 0) et d'agir en conséquence.
Extension de Jetons
Dans la section suivante, nous allons parler des avantages et des différentes Extension de Jetons actuellement présentes sur Solana, mais dans ce paragraphe d'introduction, nous allons seulement expliquer comment elles sont sérialisées et ajoutées aux deux comptes d'état dont nous avons parlé précédemment.
Chaque extension dispose d'un discriminateur qui est enregistré avec la taille de cette extension directement dans le compte. Nous appellerons cela l'"en-tête" (header) de l'extension et il ressemble à cela :
pub struct ExtensionHeader {
/// Extension Discriminator
pub discriminator: u16
/// Length of the Disriminator
pub length: u16
}
Cela permet de savoir très facilement quelles extensions se trouvent dans le jeton et de désérialiser uniquement les données dont nous avons besoin, puisqu'il suffit de récupérer le discriminateur, puis passer à l'extension suivante pour vérifier ce qui s'y trouve ou non.