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
176 changes: 176 additions & 0 deletions src/app/content/challenges/pinocchio-escrow/de/challenge.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -202,3 +202,179 @@ Die Implementierung bietet mehrere wichtige Funktionen:
5. **Dokumentation**: Klare Kommentare, die den Zweck und die Sicherheitsüberlegungen jeder Methode erläutern

Diese Implementierung stellt sicher, dass unser Escrow-Status sowohl sicher als auch effizient ist, mit angemessener Validierung und Performance-Optimierungen wo sinnvoll.


<ArticleSection name="Helpers" id="helpers" level="h2" />

Kleine `helper.rs` Funktionen zur Kontoprüfung und Verwaltung der ATA, verwendet in den Anleitungen.

```rust

pub struct SignerAccount;
impl SignerAccount {
pub fn check(account: &AccountInfo) -> Result<(), ProgramError> {
if !account.is_signer() {
return Err(ProgramError::InvalidAccountOwner);
}
Ok(())
}
}

pub struct MintInterface;
impl MintInterface {
pub fn check(account: &AccountInfo) -> Result<(), ProgramError> {
if !account.is_owned_by(&pinocchio_token::ID) {
return Err(ProgramError::IllegalOwner);
}

if account.data_len() != pinocchio_token::state::Mint::LEN {
return Err(ProgramError::InvalidAccountData);
}

Ok(())
}
}

pub struct TokenAccount;

impl TokenAccount {
pub fn check(account: &AccountInfo) -> Result<(), ProgramError> {
if !account.is_owned_by(&pinocchio_token::ID) {
return Err(ProgramError::IllegalOwner);
}

if account
.data_len()
.ne(&pinocchio_token::state::TokenAccount::LEN)
{
return Err(ProgramError::InvalidAccountData);
}

Ok(())
}
}

fn check_token_program(token_prog: &AccountInfo) -> Result<(), ProgramError> {
if token_prog.key() != &pinocchio_token::ID {
return Err(ProgramError::IncorrectProgramId);
}
Ok(())
}

fn check_system_program(system_prog: &AccountInfo) -> Result<(), ProgramError> {
if system_prog.key() != &pinocchio_system::ID {
return Err(ProgramError::IncorrectProgramId);
}
Ok(())
}

pub struct AssociatedTokenAccount;
impl AssociatedTokenAccount {
pub fn check(
account: &AccountInfo,
authority: &AccountInfo,
mint: &AccountInfo,
token_program: &AccountInfo,
) -> Result<(), ProgramError> {
TokenAccount::check(account)?;
MintInterface::check(mint)?;
check_token_program(token_program)?;

let derivedata = find_program_address(
&[authority.key(), token_program.key(), mint.key()],
&pinocchio_associated_token_account::ID,
);

if derivedata.0.ne(account.key()) {
return Err(ProgramError::InvalidAccountData);
}
Ok(())
}

pub fn init(
account: &AccountInfo,
mint: &AccountInfo,
payer: &AccountInfo,
owner: &AccountInfo,
system_program: &AccountInfo,
token_program: &AccountInfo,
) -> Result<(), ProgramError> {
MintInterface::check(mint)?;
SignerAccount::check(payer)?;
check_system_program(system_program)?;
check_token_program(token_program)?;

Create {
funding_account: payer,
account: account,
wallet: owner,
mint: mint,
system_program: system_program,
token_program: token_program,
}
.invoke()?;

Ok(())
}

pub fn init_if_needed(
account: &AccountInfo,
mint: &AccountInfo,
payer: &AccountInfo,
owner: &AccountInfo,
system_program: &AccountInfo,
token_program: &AccountInfo,
) -> Result<(), ProgramError> {
match Self::check(account, owner, mint, token_program) {
Ok(_) => Ok(()),
Err(_) => Self::init(account, mint, payer, owner, system_program, token_program),
}
}
}

pub struct ProgramAccount;

impl ProgramAccount {
pub fn check(account: &AccountInfo) -> Result<(), ProgramError> {
if !account.is_owned_by(&ID) {
return Err(ProgramError::IllegalOwner);
}
if account.data_len() != Escrow::LEN {
return Err(ProgramError::InvalidAccountData);
}
Ok(())
}

pub fn init<'a, T: Sized>(
payer: &AccountInfo,
account: &AccountInfo,
seeds: &[Seed<'a>],
space: usize,
) -> Result<(), ProgramError> {
let lamports = Rent::get()?.minimum_balance(space);

let signer = [Signer::from(seeds)];

CreateAccount {
from: payer,
to: account,
lamports,
space: space as u64,
owner: &crate::ID,
}
.invoke_signed(&signer)?;
Ok(())
}

pub fn close(account: &AccountInfo, refund_account: &AccountInfo) -> Result<(), ProgramError> {
let source_lamports = account.lamports();
*refund_account.try_borrow_mut_lamports()? += source_lamports;
*account.try_borrow_mut_lamports()? = 0;
account.resize(0)?;
account.close()?;
Ok(())
}
}

```

176 changes: 176 additions & 0 deletions src/app/content/challenges/pinocchio-escrow/en/challenge.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -202,3 +202,179 @@ The implementation provides several key features:
5. **Documentation**: Clear comments explaining the purpose and safety considerations of each method

This implementation ensures our escrow state is both safe and efficient, with proper validation and performance optimizations where appropriate.


<ArticleSection name="Helpers" id="helpers" level="h2" />

Small `helper.rs` functions for account validation and ATA management used across the instructions.

```rust

pub struct SignerAccount;
impl SignerAccount {
pub fn check(account: &AccountInfo) -> Result<(), ProgramError> {
if !account.is_signer() {
return Err(ProgramError::InvalidAccountOwner);
}
Ok(())
}
}

pub struct MintInterface;
impl MintInterface {
pub fn check(account: &AccountInfo) -> Result<(), ProgramError> {
if !account.is_owned_by(&pinocchio_token::ID) {
return Err(ProgramError::IllegalOwner);
}

if account.data_len() != pinocchio_token::state::Mint::LEN {
return Err(ProgramError::InvalidAccountData);
}

Ok(())
}
}

pub struct TokenAccount;

impl TokenAccount {
pub fn check(account: &AccountInfo) -> Result<(), ProgramError> {
if !account.is_owned_by(&pinocchio_token::ID) {
return Err(ProgramError::IllegalOwner);
}

if account
.data_len()
.ne(&pinocchio_token::state::TokenAccount::LEN)
{
return Err(ProgramError::InvalidAccountData);
}

Ok(())
}
}

fn check_token_program(token_prog: &AccountInfo) -> Result<(), ProgramError> {
if token_prog.key() != &pinocchio_token::ID {
return Err(ProgramError::IncorrectProgramId);
}
Ok(())
}

fn check_system_program(system_prog: &AccountInfo) -> Result<(), ProgramError> {
if system_prog.key() != &pinocchio_system::ID {
return Err(ProgramError::IncorrectProgramId);
}
Ok(())
}

pub struct AssociatedTokenAccount;
impl AssociatedTokenAccount {
pub fn check(
account: &AccountInfo,
authority: &AccountInfo,
mint: &AccountInfo,
token_program: &AccountInfo,
) -> Result<(), ProgramError> {
TokenAccount::check(account)?;
MintInterface::check(mint)?;
check_token_program(token_program)?;

let derivedata = find_program_address(
&[authority.key(), token_program.key(), mint.key()],
&pinocchio_associated_token_account::ID,
);

if derivedata.0.ne(account.key()) {
return Err(ProgramError::InvalidAccountData);
}
Ok(())
}

pub fn init(
account: &AccountInfo,
mint: &AccountInfo,
payer: &AccountInfo,
owner: &AccountInfo,
system_program: &AccountInfo,
token_program: &AccountInfo,
) -> Result<(), ProgramError> {
MintInterface::check(mint)?;
SignerAccount::check(payer)?;
check_system_program(system_program)?;
check_token_program(token_program)?;

Create {
funding_account: payer,
account: account,
wallet: owner,
mint: mint,
system_program: system_program,
token_program: token_program,
}
.invoke()?;

Ok(())
}

pub fn init_if_needed(
account: &AccountInfo,
mint: &AccountInfo,
payer: &AccountInfo,
owner: &AccountInfo,
system_program: &AccountInfo,
token_program: &AccountInfo,
) -> Result<(), ProgramError> {
match Self::check(account, owner, mint, token_program) {
Ok(_) => Ok(()),
Err(_) => Self::init(account, mint, payer, owner, system_program, token_program),
}
}
}

pub struct ProgramAccount;

impl ProgramAccount {
pub fn check(account: &AccountInfo) -> Result<(), ProgramError> {
if !account.is_owned_by(&ID) {
return Err(ProgramError::IllegalOwner);
}
if account.data_len() != Escrow::LEN {
return Err(ProgramError::InvalidAccountData);
}
Ok(())
}

pub fn init<'a, T: Sized>(
payer: &AccountInfo,
account: &AccountInfo,
seeds: &[Seed<'a>],
space: usize,
) -> Result<(), ProgramError> {
let lamports = Rent::get()?.minimum_balance(space);

let signer = [Signer::from(seeds)];

CreateAccount {
from: payer,
to: account,
lamports,
space: space as u64,
owner: &crate::ID,
}
.invoke_signed(&signer)?;
Ok(())
}

pub fn close(account: &AccountInfo, refund_account: &AccountInfo) -> Result<(), ProgramError> {
let source_lamports = account.lamports();
*refund_account.try_borrow_mut_lamports()? += source_lamports;
*account.try_borrow_mut_lamports()? = 0;
account.resize(0)?;
account.close()?;
Ok(())
}
}

```

Loading