1#![expect(
4 clippy::too_long_first_doc_paragraph,
5 reason = "Mysten-inherited docs sometimes have long first paragraphs."
6)]
7
8use std::str::FromStr;
9
10use eyre::eyre;
11use fastcrypto::encoding::decode_bytes_hex;
12use serde::{Deserialize, Serialize};
13use serde_repr::{Deserialize_repr, Serialize_repr};
14
15#[derive(Serialize_repr, Deserialize_repr, Copy, Clone, PartialEq, Eq, Debug, Hash)]
19#[repr(u8)]
20pub enum IntentVersion {
21 V0 = 0,
22}
23
24impl TryFrom<u8> for IntentVersion {
25 type Error = eyre::Report;
26 fn try_from(value: u8) -> Result<Self, Self::Error> {
27 bcs::from_bytes(&[value]).map_err(|_| eyre!("Invalid IntentVersion"))
28 }
29}
30
31#[derive(Serialize_repr, Deserialize_repr, Copy, Clone, PartialEq, Eq, Debug, Hash)]
36#[repr(u8)]
37pub enum AppId {
38 Sui = 0,
39 Narwhal = 1,
40 Consensus = 2,
41}
42
43impl 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::Sui
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, HeaderDigest = 6, BridgeEventUnused = 7, ConsensusBlock = 8, }
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 FromStr for Intent {
93 type Err = eyre::Report;
94 fn from_str(s: &str) -> Result<Self, Self::Err> {
95 let s: Vec<u8> = decode_bytes_hex(s).map_err(|_| eyre!("Invalid Intent"))?;
96 if s.len() != 3 {
97 return Err(eyre!("Invalid Intent"));
98 }
99 Ok(Self {
100 scope: s[0].try_into()?,
101 version: s[1].try_into()?,
102 app_id: s[2].try_into()?,
103 })
104 }
105}
106
107impl Intent {
108 pub const fn sui_app(scope: IntentScope) -> Self {
109 Self {
110 version: IntentVersion::V0,
111 scope,
112 app_id: AppId::Sui,
113 }
114 }
115
116 pub const fn sui_transaction() -> Self {
117 Self {
118 scope: IntentScope::TransactionData,
119 version: IntentVersion::V0,
120 app_id: AppId::Sui,
121 }
122 }
123
124 pub const fn personal_message() -> Self {
125 Self {
126 scope: IntentScope::PersonalMessage,
127 version: IntentVersion::V0,
128 app_id: AppId::Sui,
129 }
130 }
131
132 pub const fn narwhal_app(scope: IntentScope) -> Self {
133 Self {
134 scope,
135 version: IntentVersion::V0,
136 app_id: AppId::Narwhal,
137 }
138 }
139
140 pub const fn consensus_app(scope: IntentScope) -> Self {
141 Self {
142 scope,
143 version: IntentVersion::V0,
144 app_id: AppId::Consensus,
145 }
146 }
147}
148
149#[derive(Debug, PartialEq, Eq, Serialize, Clone, Hash, Deserialize)]
158pub struct IntentMessage<T> {
159 pub intent: Intent,
160 pub value: T,
161}
162
163impl<T> IntentMessage<T> {
164 pub const fn new(intent: Intent, value: T) -> Self {
165 Self { intent, value }
166 }
167}