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