mpl_token_auth_rules/
payload.rs

1//! The definition and associated functions of the `Payload` type that is passed from the program client to the auth rules program for validation.
2use crate::error::RuleSetError;
3use borsh::{BorshDeserialize, BorshSerialize};
4use serde::{Deserialize, Serialize};
5use solana_program::{entrypoint::ProgramResult, pubkey::Pubkey};
6use std::collections::HashMap;
7
8#[repr(C)]
9#[derive(BorshSerialize, BorshDeserialize, Serialize, Deserialize, PartialEq, Eq, Debug, Clone)]
10/// A seed path type used by the `DerivedKeyMatch` rule.
11pub struct SeedsVec {
12    /// The vector of derivation seeds.
13    pub seeds: Vec<Vec<u8>>,
14}
15
16impl SeedsVec {
17    /// Create a new `SeedsVec`.
18    pub fn new(seeds: Vec<Vec<u8>>) -> Self {
19        Self { seeds }
20    }
21}
22
23#[repr(C)]
24#[derive(BorshSerialize, BorshDeserialize, Serialize, Deserialize, PartialEq, Eq, Debug, Clone)]
25/// A proof type used by the `PubkeyTreeMatch` rule.
26pub struct ProofInfo {
27    /// The merkle proof.
28    pub proof: Vec<[u8; 32]>,
29}
30
31impl ProofInfo {
32    /// Create a new `ProofInfo`.
33    pub fn new(proof: Vec<[u8; 32]>) -> Self {
34        Self { proof }
35    }
36}
37
38#[repr(C)]
39#[derive(BorshSerialize, BorshDeserialize, Serialize, Deserialize, PartialEq, Eq, Debug, Clone)]
40/// Variants representing the different types represented in a payload.
41pub enum PayloadType {
42    /// A plain `Pubkey`.
43    Pubkey(Pubkey),
44    /// PDA derivation seeds.
45    Seeds(SeedsVec),
46    /// A merkle proof.
47    MerkleProof(ProofInfo),
48    /// A plain `u64` used for `Amount`.
49    Number(u64),
50}
51
52#[repr(C)]
53#[derive(
54    BorshSerialize, BorshDeserialize, Serialize, Deserialize, PartialEq, Eq, Debug, Clone, Default,
55)]
56/// A wrapper type for the payload hashmap.
57pub struct Payload {
58    map: HashMap<String, PayloadType>,
59}
60
61impl Payload {
62    /// Create a new empty `Payload`.
63    pub fn new() -> Self {
64        Self {
65            map: HashMap::new(),
66        }
67    }
68
69    /// Create a `Payload` from an array of key-value pairs, specified as
70    /// `(PayloadKey, PayloadType)` tuples.
71    pub fn from<const N: usize>(arr: [(String, PayloadType); N]) -> Self {
72        Self {
73            map: HashMap::from(arr),
74        }
75    }
76
77    /// Inserts a key-value pair into the `Payload`.  If the `Payload` did not have this key
78    ///  present, then `None` is returned.  If the `Payload` did have this key present, the value
79    /// is updated, and the old value is returned.  The key is not updated, though; this matters
80    /// for types that can be `==` without being identical.  See `std::collections::HashMap`
81    /// documentation for more info.
82    pub fn insert(&mut self, key: String, value: PayloadType) -> Option<PayloadType> {
83        self.map.insert(key, value)
84    }
85
86    /// Tries to insert a key-value pair into a `Payload`.  If this key is already in the `Payload`
87    /// nothing is updated and an error is returned.
88    pub fn try_insert(&mut self, key: String, value: PayloadType) -> ProgramResult {
89        if self.map.get(&key).is_none() {
90            self.map.insert(key, value);
91            Ok(())
92        } else {
93            Err(RuleSetError::ValueOccupied.into())
94        }
95    }
96
97    /// Returns a reference to the value corresponding to the key.
98    pub fn get(&self, key: &String) -> Option<&PayloadType> {
99        self.map.get(key)
100    }
101
102    /// Get a reference to the `Pubkey` associated with a key, if and only if the `Payload` value
103    /// is the `PayloadType::Pubkey` variant.  Returns `None` if the key is not present in the
104    /// `Payload` or the value is a different `PayloadType` variant.
105    pub fn get_pubkey(&self, key: &String) -> Option<&Pubkey> {
106        if let Some(val) = self.map.get(key) {
107            match val {
108                PayloadType::Pubkey(pubkey) => Some(pubkey),
109                _ => None,
110            }
111        } else {
112            None
113        }
114    }
115
116    /// Get a reference to the `SeedsVec` associated with a key, if and only if the `Payload` value
117    /// is the `PayloadType::Seeds` variant.  Returns `None` if the key is not present in the
118    /// `Payload` or the value is a different `PayloadType` variant.
119    pub fn get_seeds(&self, key: &String) -> Option<&SeedsVec> {
120        if let Some(val) = self.map.get(key) {
121            match val {
122                PayloadType::Seeds(seeds) => Some(seeds),
123                _ => None,
124            }
125        } else {
126            None
127        }
128    }
129
130    /// Get a reference to the `ProofInfo` associated with a key, if and only if the `Payload` value
131    /// is the `PayloadType::MerkleProof` variant.  Returns `None` if the key is not present in the
132    /// `Payload` or the value is a different `PayloadType` variant.
133    pub fn get_merkle_proof(&self, key: &String) -> Option<&ProofInfo> {
134        if let Some(val) = self.map.get(key) {
135            match val {
136                PayloadType::MerkleProof(proof_info) => Some(proof_info),
137                _ => None,
138            }
139        } else {
140            None
141        }
142    }
143
144    /// Get the `u64` associated with a key, if and only if the `Payload` value is the
145    /// `PayloadType::Number` variant.  Returns `None` if the key is not present in the `Payload`
146    /// or the value is a different `PayloadType` variant.
147    pub fn get_amount(&self, key: &String) -> Option<u64> {
148        if let Some(val) = self.map.get(key) {
149            match val {
150                PayloadType::Number(number) => Some(*number),
151                _ => None,
152            }
153        } else {
154            None
155        }
156    }
157}