1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
use solana_program::{msg, system_program};
use crate::{
error::RuleSetError,
state::{try_from_bytes, RuleResult},
state::{
v2::{Constraint, ConstraintType, Str32, HEADER_SECTION},
Header,
},
};
/// Constraint that represents a test on whether a pubkey can be signed from a client and therefore
/// is a true wallet account or not.
///
/// The details of this constraint are as follows: a wallet is defined as being both owned by the
/// System Program and the address is on-curve. The `field` value in the rule is used to
/// locate the `Pubkey` in the payload that must be on-curve and for which the owner must be
/// the System Program. Note this same `Pubkey` account must also be provided to `Validate`
/// via the `additional_rule_accounts` argument. This is so that the `Pubkey`'s owner can be
/// found from its `AccountInfo` struct.
pub struct IsWallet<'a> {
/// The field in the `Payload` to be checked.
pub field: &'a Str32,
}
impl<'a> IsWallet<'a> {
/// Deserialize a constraint from a byte array.
pub fn from_bytes(bytes: &'a [u8]) -> Result<Self, RuleSetError> {
let field = try_from_bytes::<Str32>(0, Str32::SIZE, bytes)?;
Ok(Self { field })
}
/// Serialize a constraint into a byte array.
pub fn serialize(field: String) -> Result<Vec<u8>, RuleSetError> {
let mut data = Vec::with_capacity(HEADER_SECTION + Str32::SIZE);
// Header
Header::serialize(ConstraintType::IsWallet, Str32::SIZE as u32, &mut data);
// Constraint
// - field
let mut field_bytes = [0u8; Str32::SIZE];
field_bytes[..field.len()].copy_from_slice(field.as_bytes());
data.extend(field_bytes);
Ok(data)
}
}
impl<'a> Constraint<'a> for IsWallet<'a> {
fn constraint_type(&self) -> ConstraintType {
ConstraintType::IsWallet
}
fn validate(
&self,
accounts: &std::collections::HashMap<
solana_program::pubkey::Pubkey,
&solana_program::account_info::AccountInfo,
>,
payload: &crate::payload::Payload,
_update_rule_state: bool,
_rule_set_state_pda: &Option<&solana_program::account_info::AccountInfo>,
_rule_authority: &Option<&solana_program::account_info::AccountInfo>,
) -> RuleResult {
msg!("Validating IsWallet");
// Get the `Pubkey` we are checking from the payload.
let key = match payload.get_pubkey(&self.field.to_string()) {
Some(pubkey) => pubkey,
_ => return RuleResult::Error(RuleSetError::MissingPayloadValue.into()),
};
// Get the `AccountInfo` struct for the `Pubkey` and verify that
// its owner is the System Program.
if let Some(account) = accounts.get(key) {
if *account.owner != system_program::ID {
// TODO: Change error return to commented line after on-curve syscall
// available.
return RuleResult::Error(RuleSetError::NotImplemented.into());
//return (false, self.to_error());
}
} else {
return RuleResult::Error(RuleSetError::MissingAccount.into());
}
// TODO: Uncomment call to `is_on_curve()` after on-curve sycall available.
RuleResult::Error(RuleSetError::NotImplemented.into())
//(is_on_curve(key), self.to_error())
}
}