1use std::str::FromStr;
6
7use eyre::eyre;
8use fastcrypto::encoding::decode_bytes_hex;
9use serde::{Deserialize, Serialize};
10use serde_repr::{Deserialize_repr, Serialize_repr};
11
12pub const INTENT_PREFIX_LENGTH: usize = 3;
13
14#[derive(Serialize_repr, Deserialize_repr, Copy, Clone, PartialEq, Eq, Debug, Hash)]
18#[repr(u8)]
19pub enum IntentVersion {
20 V0 = 0,
21}
22
23impl TryFrom<u8> for IntentVersion {
24 type Error = eyre::Report;
25 fn try_from(value: u8) -> Result<Self, Self::Error> {
26 bcs::from_bytes(&[value]).map_err(|_| eyre!("Invalid IntentVersion"))
27 }
28}
29
30#[derive(Serialize_repr, Deserialize_repr, Copy, Clone, PartialEq, Eq, Debug, Hash)]
36#[repr(u8)]
37pub enum AppId {
38 Iota = 0,
39 Consensus = 1,
40}
41
42impl TryFrom<u8> for AppId {
44 type Error = eyre::Report;
45 fn try_from(value: u8) -> Result<Self, Self::Error> {
46 bcs::from_bytes(&[value]).map_err(|_| eyre!("Invalid AppId"))
47 }
48}
49
50impl Default for AppId {
51 fn default() -> Self {
52 Self::Iota
53 }
54}
55
56#[derive(Serialize_repr, Deserialize_repr, Copy, Clone, PartialEq, Eq, Debug, Hash)]
60#[repr(u8)]
61pub enum IntentScope {
62 TransactionData = 0, TransactionEffects = 1, CheckpointSummary = 2, PersonalMessage = 3, SenderSignedTransaction = 4, ProofOfPossession = 5, BridgeEventDeprecated = 6, ConsensusBlock = 7, DiscoveryPeers = 8, AuthorityCapabilities = 9, }
75
76impl TryFrom<u8> for IntentScope {
77 type Error = eyre::Report;
78 fn try_from(value: u8) -> Result<Self, Self::Error> {
79 bcs::from_bytes(&[value]).map_err(|_| eyre!("Invalid IntentScope"))
80 }
81}
82
83#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone, Hash)]
92pub struct Intent {
93 pub scope: IntentScope,
94 pub version: IntentVersion,
95 pub app_id: AppId,
96}
97
98impl Intent {
99 pub fn to_bytes(&self) -> [u8; INTENT_PREFIX_LENGTH] {
100 [self.scope as u8, self.version as u8, self.app_id as u8]
101 }
102
103 pub fn from_bytes(bytes: &[u8]) -> Result<Self, eyre::Report> {
104 if bytes.len() != INTENT_PREFIX_LENGTH {
105 return Err(eyre!("Invalid Intent"));
106 }
107 Ok(Self {
108 scope: bytes[0].try_into()?,
109 version: bytes[1].try_into()?,
110 app_id: bytes[2].try_into()?,
111 })
112 }
113}
114
115impl FromStr for Intent {
116 type Err = eyre::Report;
117 fn from_str(s: &str) -> Result<Self, Self::Err> {
118 let bytes: Vec<u8> = decode_bytes_hex(s).map_err(|_| eyre!("Invalid Intent"))?;
119 Self::from_bytes(bytes.as_slice())
120 }
121}
122
123impl Intent {
124 pub fn iota_app(scope: IntentScope) -> Self {
125 Self {
126 version: IntentVersion::V0,
127 scope,
128 app_id: AppId::Iota,
129 }
130 }
131
132 pub fn iota_transaction() -> Self {
133 Self {
134 scope: IntentScope::TransactionData,
135 version: IntentVersion::V0,
136 app_id: AppId::Iota,
137 }
138 }
139
140 pub fn personal_message() -> Self {
141 Self {
142 scope: IntentScope::PersonalMessage,
143 version: IntentVersion::V0,
144 app_id: AppId::Iota,
145 }
146 }
147
148 pub fn consensus_app(scope: IntentScope) -> Self {
149 Self {
150 scope,
151 version: IntentVersion::V0,
152 app_id: AppId::Consensus,
153 }
154 }
155}
156
157#[derive(Debug, PartialEq, Eq, Serialize, Clone, Hash, Deserialize)]
166pub struct IntentMessage<T> {
167 pub intent: Intent,
168 pub value: T,
169}
170
171impl<T> IntentMessage<T> {
172 pub fn new(intent: Intent, value: T) -> Self {
173 Self { intent, value }
174 }
175}
176
177#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
179pub struct PersonalMessage {
180 pub message: Vec<u8>,
181}
182
183pub trait SecureIntent: Serialize + private::SealedIntent {}
184
185pub(crate) mod private {
186 use super::IntentMessage;
187
188 pub trait SealedIntent {}
189 impl<T> SealedIntent for IntentMessage<T> {}
190}
191
192#[derive(Serialize_repr, Deserialize_repr, Copy, Clone, PartialEq, Eq, Debug, Hash)]
197#[repr(u8)]
198pub enum HashingIntentScope {
199 ChildObjectId = 0xf0,
200 RegularObjectId = 0xf1,
201}