開啟保管庫
open 指令會建立一個程式衍生地址(PDA)保管庫,用於安全存放 lamports。此 PDA 使用經過雜湊的公鑰作為種子,確保只有原始密鑰的持有者才能稍後提取資金。
PDA 提供了一種安全存放資金的方法,因為:
只有您的程式可以控制該帳戶(不存在私鑰)
保管庫地址是從用戶的雜湊確定性衍生的
提款只能通過您的程式邏輯進行
所需帳戶
該指令需要以下帳戶:
payer:支付保管庫建立費用(必須是簽署者且可變)vault:正在初始化的 PDA(必須可變)system_program:帳戶建立所需(必須可執行)
在程式碼中,這看起來像這樣:
rust
pub struct OpenVaultAccounts<'a> {
pub payer: &'a AccountInfo,
pub vault: &'a AccountInfo,
}
impl<'a> TryFrom<&'a [AccountInfo]> for OpenVaultAccounts<'a> {
type Error = ProgramError;
fn try_from(accounts: &'a [AccountInfo]) -> Result<Self, Self::Error> {
let [payer, vault, _system_program] = accounts else {
return Err(ProgramError::NotEnoughAccountKeys);
};
Ok(Self { payer, vault })
}
}指令數據
需要兩個數據:
hash:用戶 winternitz 密鑰對公鑰的 SHA-256 雜湊值([u8; 32])bump:從客戶端傳遞的 PDA 衍生 bump(u8)
以下是程式碼中的示例:
rust
pub struct OpenVaultInstructionData {
pub hash: [u8; 32],
pub bump: [u8; 1],
}
impl<'a> TryFrom<&'a [u8]> for OpenVaultInstructionData {
type Error = ProgramError;
fn try_from(data: &'a [u8]) -> Result<Self, Self::Error> {
if data.len() != core::mem::size_of::<OpenVaultInstructionData>() {
return Err(ProgramError::InvalidInstructionData);
}
let hash = data[0..32].try_into().map_err(|_| ProgramError::InvalidInstructionData)?;
let bump = data[32..33].try_into().map_err(|_| ProgramError::InvalidInstructionData)?;
Ok(Self { hash, bump })
}
}指令邏輯
該指令會建立一個分配給我們程式的空 PDA。雖然該帳戶不包含任何數據,但程式擁有權確保提款只能通過我們控制的邏輯進行。
以下是程式碼中的示例:
rust
pub struct OpenVault<'a> {
pub accounts: OpenVaultAccounts<'a>,
pub instruction_data: OpenVaultInstructionData,
}
impl<'a> TryFrom<(&'a [u8], &'a [AccountInfo])> for OpenVault<'a> {
type Error = ProgramError;
fn try_from((data, accounts): (&'a [u8], &'a [AccountInfo])) -> Result<Self, Self::Error> {
let instruction_data = OpenVaultInstructionData::try_from(data)?;
let accounts = OpenVaultAccounts::try_from(accounts)?;
Ok(Self { accounts, instruction_data })
}
}
impl<'a> OpenVault<'a> {
pub const DISCRIMINATOR: &'a u8 = &0;
pub fn process(&self) -> ProgramResult {
let lamports = Rent::get()?.minimum_balance(0);
let seeds = [Seed::from(&self.instruction_data.hash), Seed::from(&self.instruction_data.bump)];
// Create our vault
CreateAccount {
from: self.accounts.payer,
to: self.accounts.vault,
lamports,
space: 0,
owner: &crate::ID,
}
.invoke_signed(&[Signer::from(&seeds)])
}
}