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}