Deposit
L'instruction deposit effectue trois tâches principales :
Dépose les jetons
mint_xetmint_yen fonction du montant de LP que l'utilisateur souhaitemint.Calcule le montant à déposer et vérifie qu'il n'est pas supérieur aux valeurs
max_xetmax_ydéfinies par l'utilisateur.Mint la quantité appropriée de
mint_lpdans l'ATA de l'utilisateur.
Comptes Nécessaires
Voici les comptes nécessaires pour ce contexte :
user: L'utilisateur qui dépose des jetons dans la liquidité de l'Amm. Doit êtresigner.mint_lp: Le compte de Mint qui représentera la liquidité de la pool. Doit êtremutable.vault_x: Le compte de jetons qui détient tous les jetons X déposés dans la pool. Doit êtremutable.vault_y: Le compte de jetons qui détient tous les jetons Y déposés dans la pool. Doit êtremutable.user_x_ata: Le compte de jeton associé de l'utilisateur pour le jeton X. Il s'agit du compte source à partir duquel le jeton X de l'utilisateur sera transféré dans la pool. Doit êtremutable.user_y_ata: Le compte de jeton associé de l'utilisateur pour le jeton Y. Il s'agit du compte source à partir duquel le jeton Y de l'utilisateur sera transféré dans la pool. Doit êtremutable.user_lp_ata: Le compte de jetons associé de l'utilisateur pour les jetons LP. Il s'agit du compte de destination dans lequel les jetons LP seront créés. Doit êtremutable.config: Le compte de configuration de la pool de l'AMM. Stocke tous les paramètres pertinents et l'état de la pool.token program: Le compte du program SPL-Token. Cela est nécessaire pour effectuer des opérations liées aux jetons telles que les transferts et la création. Doit êtreexecutable.
Ici encore, je vous laisse le soin de l'implémenter :
pub struct DepositAccounts<'a> {
pub user: &'a AccountInfo,
pub mint_lp: &'a AccountInfo,
pub vault_x: &'a AccountInfo,
pub vault_y: &'a AccountInfo,
pub user_x_ata: &'a AccountInfo,
pub user_y_ata: &'a AccountInfo,
pub user_lp_ata: &'a AccountInfo,
pub config: &'a AccountInfo,
pub token_program: &'a AccountInfo,
}
impl<'a> TryFrom<&'a [AccountInfo]> for DepositAccounts<'a> {
type Error = ProgramError;
fn try_from(accounts: &'a [AccountInfo]) -> Result<Self, Self::Error> {
//..
}
}Données d'Instruction
Voici les données d'instruction que nous devons transmettre :
amount: Le montant de jetons LP que l'utilisateur souhaite recevoir. Doit être un[u64]max_x: Le montant maximal de jetons X que l'utilisateur est prêt à déposer. Doit être un[u64]max_y: Le montant maximal de jetons Y que l'utilisateur est prêt à déposer. Doit être un[u64]expiration: L'expiration de cet ordre. Il est important de s'assurer que la transaction doit être effectuée dans un certain délai. Doit être un[i64]
Nous allons gérer l'implémentation de DepositInstructionData de la même manière que l'initialisation. Je vous laisse donc le soin de l'implémenter :
pub struct DepositInstructionData {
pub amount: u64,
pub max_x: u64,
pub max_y: u64,
pub expiration: i64,
}
impl<'a> TryFrom<&'a [u8]> for DepositInstructionData {
type Error = ProgramError;
fn try_from(data: &'a [u8]) -> Result<Self, Self::Error> {
//..
}
}Logique d'Instruction
Nous commençons par désérialiser les instruction_data et les accounts.
Nous devons ensuite :
Chargez le compte
Configpour récupérer toutes les données qu'il contient. Nous pouvons le faire à l'aide deConfig::load().Vérifiez que
AmmStateest valide (donc si c'est égal àAmmState::Initialized)Vérifiez que la dérivation de
vault_xetvault_ycorrespond bien à des Comptes de Jetons Associés, comme ceci :
// Check if the vault_x is valid
let (vault_x, _) = find_program_address(
&[
self.accounts.config.key(),
self.accounts.token_program.key(),
config.mint_x(),
],
&pinocchio_associated_token_account::ID,
);
if vault_x.ne(self.accounts.vault_x.key()) {
return Err(ProgramError::InvalidAccountData);
}Désérialisez tous les comptes de jetons impliqués et utilisez les données qu'ils contiennent pour calculer le montant des dépôts à l'aide du crate
constant-product-curveet vérifiez le slippage comme ceci :
// Deserialize the token accounts
let mint_lp = unsafe { Mint::from_account_info_unchecked(self.accounts.mint_lp)? };
let vault_x = unsafe { TokenAccount::from_account_info_unchecked(self.accounts.vault_x)? };
let vault_y = unsafe { TokenAccount::from_account_info_unchecked(self.accounts.vault_y)? };
// Grab the amounts to deposit
let (x, y) = match mint_lp.supply() == 0 && vault_x.amount() == 0 && vault_y.amount() == 0 {
true => (self.instruction_data.max_x, self.instruction_data.max_y),
false => {
let amounts = ConstantProduct::xy_deposit_amounts_from_l(
vault_x.amount(),
vault_y.amount(),
mint_lp.supply(),
self.instruction_data.amount,
6,
)
.map_err(|_| ProgramError::InvalidArgument)?;
(amounts.x, amounts.y)
}
};
// Check for slippage
if !(x <= self.instruction_data.max_x && y <= self.instruction_data.max_y) {
return Err(ProgramError::InvalidArgument);
}Transférer les montants des comptes de jetons de l'utilisateur vers les vaults et mintez le montant approprié de jetons LP sur le compte de jetons de l'utilisateur.
Vous devriez être suffisamment compétent pour le faire vous-même, je vous laisse donc le soin de l'implémenter :
pub struct Deposit<'a> {
pub accounts: DepositAccounts<'a>,
pub instruction_data: DepositInstructionData,
}
impl<'a> TryFrom<(&'a [u8], &'a [AccountInfo])> for Deposit<'a> {
type Error = ProgramError;
fn try_from((data, accounts): (&'a [u8], &'a [AccountInfo])) -> Result<Self, Self::Error> {
let accounts = DepositAccounts::try_from(accounts)?;
let instruction_data = DepositInstructionData::try_from(data)?;
// Return the initialized struct
Ok(Self {
accounts,
instruction_data,
})
}
}
impl<'a> Deposit<'a> {
pub const DISCRIMINATOR: &'a u8 = &1;
pub fn process(&mut self) -> ProgramResult {
//..
Ok(())
}
}