Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions pinocchio/interface/src/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -504,10 +504,17 @@ pub enum TokenInstruction {
///
/// Accounts expected by this instruction:
///
/// * Single owner/delegate
/// 0. `[writable]` The source account.
/// 1. `[writable]` The destination account.
/// 2. `[signer]` The source account's owner/delegate.
///
/// * Multisignature owner/delegate
/// 0. `[writable]` The source account.
/// 1. `[writable]` The destination account.
/// 2. `[]` The source account's multisignature owner/delegate.
/// 3. `..+M` `[signer]` M signer accounts.
///
/// Data expected by this instruction:
///
/// - `Option<u64>` The amount of lamports to transfer. When an amount is
Expand Down
30 changes: 25 additions & 5 deletions pinocchio/program/src/processor/unwrap_lamports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,6 @@ pub fn process_unwrap_lamports(accounts: &[AccountInfo], instruction_data: &[u8]
return Err(TokenError::NonNativeNotSupported.into());
}

// SAFETY: `authority_info` is not currently borrowed; in the case
// `authority_info` is the same as `source_account_info`, then it cannot be
// a multisig.
unsafe { validate_owner(&source_account.owner, authority_info, remaining)? };

// If we have an amount, we need to validate whether there are enough lamports
// to unwrap or not; otherwise we just use the full amount.
let (amount, remaining_amount) = if let Some(amount) = maybe_amount {
Expand All @@ -60,6 +55,31 @@ pub fn process_unwrap_lamports(accounts: &[AccountInfo], instruction_data: &[u8]
(source_account.amount(), 0)
};

// Validates the authority (delegate or owner).

if source_account.delegate() == Some(authority_info.key()) {
// SAFETY: `authority_info` is not currently borrowed; in the case
// `authority_info` is the same as `source_account_info`, then it cannot be
// a multisig.
unsafe { validate_owner(authority_info.key(), authority_info, remaining)? };

let delegated_amount = source_account
.delegated_amount()
.checked_sub(amount)
.ok_or(TokenError::InsufficientFunds)?;

source_account.set_delegated_amount(delegated_amount);

if delegated_amount == 0 {
source_account.clear_delegate();
}
} else {
// SAFETY: `authority_info` is not currently borrowed; in the case
// `authority_info` is the same as `source_account_info`, then it cannot be
// a multisig.
unsafe { validate_owner(&source_account.owner, authority_info, remaining)? };
}

if unlikely(amount == 0) {
// Validates the token account owner since we are not writing
// to the account.
Expand Down
Loading