penumbra_sdk_transaction/plan/
memo.rs1use anyhow::Context;
2use penumbra_sdk_keys::{symmetric::PayloadKey, Address};
3use penumbra_sdk_proto::{core::transaction::v1 as pb, DomainType};
4
5use rand::{CryptoRng, RngCore};
6
7use crate::memo::{MemoCiphertext, MemoPlaintext};
8
9#[derive(Clone, Debug)]
10pub struct MemoPlan {
11 pub plaintext: MemoPlaintext,
12 pub key: PayloadKey,
13}
14
15impl MemoPlan {
16 pub fn new<R: CryptoRng + RngCore>(rng: &mut R, plaintext: MemoPlaintext) -> MemoPlan {
18 let key = PayloadKey::random_key(rng);
19 MemoPlan { plaintext, key }
20 }
21
22 pub fn memo(&self) -> anyhow::Result<MemoCiphertext> {
24 MemoCiphertext::encrypt(self.key.clone(), &self.plaintext)
25 }
26}
27
28impl DomainType for MemoPlan {
29 type Proto = pb::MemoPlan;
30}
31
32impl From<MemoPlan> for pb::MemoPlan {
33 fn from(msg: MemoPlan) -> Self {
34 let return_address = Some(msg.plaintext.return_address().into());
35 let text = msg.plaintext.text().to_owned();
36 Self {
37 plaintext: Some(pb::MemoPlaintext {
38 return_address,
39 text,
40 }),
41 key: msg.key.to_vec(),
42 }
43 }
44}
45
46impl TryFrom<pb::MemoPlan> for MemoPlan {
47 type Error = anyhow::Error;
48
49 fn try_from(msg: pb::MemoPlan) -> Result<Self, Self::Error> {
50 let sender: Address = msg
51 .plaintext
52 .clone()
53 .ok_or_else(|| anyhow::anyhow!("memo plan missing memo plaintext"))?
54 .return_address
55 .ok_or_else(|| anyhow::anyhow!("memo plaintext missing return address"))?
56 .try_into()
57 .context("return address malformed")?;
58
59 let text: String = msg
60 .plaintext
61 .ok_or_else(|| anyhow::anyhow!("memo plan missing memo plaintext"))?
62 .text;
63
64 let key = PayloadKey::try_from(msg.key.to_vec())?;
65
66 Ok(Self {
67 plaintext: MemoPlaintext::new(sender, text)?,
68 key,
69 })
70 }
71}