
O Programa Token2022
O Programa Token2022, também conhecido como Token Extensions, é um superconjunto das funcionalidades fornecidas pelo Token Program.
O Legacy Token Program atende à maioria das necessidades para tokens fungíveis e não fungíveis através de um conjunto simples de interfaces e estruturas agnósticas. No entanto, ele carece de funcionalidades e implementações mais específicas que ajudariam os desenvolvedores a criar comportamentos personalizados com uma interface comum, tornando o desenvolvimento mais rápido e seguro.
Por esse exato motivo, um novo Token Program chamado Token2022 foi criado com um novo conjunto de funcionalidades chamadas Token Extensions. Essas extensões fornecem comportamentos específicos e customizáveis que podem ser anexados tanto à Token Account quanto à Mint Account.
Contas Mint e Token
Na seção anterior falamos sobre o fato de que a principal diferença entre os programas Tokenkeg e Token2022 são as Token Extensions.
Para serem aplicáveis, essas extensões precisam residir diretamente dentro das contas Mint e Token, já que esta é a única forma de garantir que o conjunto de regras seja aplicado durante a operação direta no programa de token.
Por esse motivo, vamos examinar as principais diferenças entre os programas de token legado e novo nessas contas.
Contas do Token Program Legado
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Mint {
/// Autoridade opcional usada para cunhar novos tokens. A autoridade de cunhagem só pode
/// ser fornecida durante a criação do mint. Se nenhuma autoridade de cunhagem estiver presente,
/// o mint tem uma oferta fixa e nenhum token adicional pode ser cunhado.
pub mint_authority: COption<Pubkey>,
/// Oferta total de tokens.
pub supply: u64,
/// Número de dígitos na base 10 à direita da casa decimal.
pub decimals: u8,
/// É `true` se esta estrutura foi inicializada
pub is_initialized: bool,
/// Autoridade opcional para congelar contas de token.
pub freeze_authority: COption<Pubkey>,
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Account {
/// O mint associado a esta conta
pub mint: Pubkey,
/// O proprietário desta conta.
pub owner: Pubkey,
/// A quantidade de tokens que esta conta possui.
pub amount: u64,
/// Se `delegate` é `Some`, então `delegated_amount` representa
/// a quantidade autorizada pelo delegado
pub delegate: COption<Pubkey>,
/// O estado da conta
pub state: AccountState,
/// Se `is_native.is_some`, este é um token nativo, e o valor registra a
/// reserva de isenção de aluguel. Uma Account precisa ser isenta de aluguel, então
/// o valor é usado pelo Processor para garantir que contas de SOL encapsulado
/// não caiam abaixo deste limite.
pub is_native: COption<u64>,
/// A quantidade delegada
pub delegated_amount: u64,
/// Autoridade opcional para fechar a conta.
pub close_authority: COption<Pubkey>,
}Como você pode ver, para essas contas não há discriminador escrito. Isso acontece porque os campos são todos de comprimento fixo e a diferença de espaço é grande o suficiente para discriminar entre esses diferentes tipos de contas apenas comparando seus comprimentos.
O problema com o Token Extension Program é que qualquer dado adicional necessário para a extensão é anexado ao final das contas Mint e Token com as quais estamos familiarizados.
Isso significa que a discriminação por comprimento seria insuficiente porque poderíamos ter um Mint com 3-4 extensões anexadas que ultrapassa o comprimento da conta Token. Por esse motivo, quando as contas Mint e Token têm extensões, um discriminador é adicionado a elas assim:
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Mint {
/// Dados do Legacy Token Program
/// ...
/// Padding (83 bytes vazios)
pub padding: [u8; 83]
/// Discriminador (1)
pub discriminator: u8
/// Dados das extensões
/// ...
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Account {
/// Dados do Legacy Token Program
/// ...
/// Discriminador (2)
pub discriminator: u8
/// Dados das extensões
/// ...
}Para manter a struct legada, o discriminador não reside no primeiro byte como de costume, mas reside no byte 166.
Isso ocorre porque o comprimento da conta Token é de 165 bytes, significando que o discriminador é adicionado após o comprimento base. Para a conta Mint, isso significa que tivemos que adicionar 83 bytes de padding para garantir que as duas contas tenham o mesmo comprimento base.
Então, para discriminar entre as duas contas, basta verificar o 166º byte (data[165] se você contar a partir de 0) e proceder conforme apropriado.
Token Extensions
Na próxima seção vamos falar sobre os méritos e as diferentes Token Extensions que estão presentes na Solana atualmente, mas neste parágrafo introdutório vamos apenas falar sobre como elas são serializadas e adicionadas às duas contas de estado que discutimos antes.
Cada extensão tem um discriminador que é salvo junto com o tamanho dessa extensão diretamente na conta. Chamaremos isso de "cabeçalho" da extensão e ele se parece com isto:
pub struct ExtensionHeader {
/// Discriminador da Extensão
pub discriminator: u16
/// Comprimento do Discriminador
pub length: u16
}Isso torna extremamente fácil saber quais extensões estão no token e desserializar apenas os dados das que precisamos, porque podemos capturar o discriminador e então pular para a próxima extensão para verificar o que está ou não lá.