Repay
The repay instruction completes our flash loan cycle by ensuring the borrowed funds are returned with appropriate fees. This instruction performs two essential steps:
Extract loan amount: Use instruction introspection to retrieve the original
amount_borrowedfrom the borrow instruction's dataTransfer funds back: Calculate the
feeand transfer the borrowed amount plus fee back to the protocol
Instruction Introspection
First, we need to examine the first instruction in the transaction to extract the original loan amount:
let ixs = ctx.accounts.instructions.to_account_info();
let mut amount_borrowed: u64;
if let Ok(borrow_ix) = load_instruction_at_checked(0, &ixs) {
// Check the amount borrowed:
let mut borrowed_data: [u8;8] = [0u8;8];
borrowed_data.copy_from_slice(&borrow_ix.data[8..16]);
amount_borrowed = u64::from_le_bytes(borrowed_data)
} else {
return Err(ProtocolError::MissingBorrowIx.into());
}Transfer Funds
Next, we calculate the protocol fee and transfer the total amount back:
// Add the fee to the amount borrowed (In our case we hardcoded it to 500 basis point)
let fee = (amount_borrowed as u128).checked_mul(500).unwrap().checked_div(10_000).ok_or(ProtocolError::Overflow)? as u64;
amount_borrowed = amount_borrowed.checked_add(fee).ok_or(ProtocolError::Overflow)?;
// Transfer the funds from the protocol to the borrower
transfer(
CpiContext::new(ctx.accounts.token_program.to_account_info(), Transfer {
from: ctx.accounts.borrower_ata.to_account_info(),
to: ctx.accounts.protocol_ata.to_account_info(),
authority: ctx.accounts.borrower.to_account_info(),
}),
amount_borrowed
)?;Our fee is hard coded to 500 basis point, and we perform "checked" math to make sure that the amount doesn't overflow which could be exploited with very large numbers. Additionally, we convert the amount to u128 for the multiplication to prevent intermediate overflow, then we safely cast back to u64