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, Default)]
36#[repr(u8)]
37pub enum AppId {
38 #[default]
39 Sui = 0,
40 Narwhal = 1,
41 Consensus = 2,
42}
43
44impl TryFrom<u8> for AppId {
45 type Error = eyre::Report;
46 fn try_from(value: u8) -> Result<Self, Self::Error> {
47 bcs::from_bytes(&[value]).map_err(|_| eyre!("Invalid AppId"))
48 }
49}
50
51#[derive(Serialize_repr, Deserialize_repr, Copy, Clone, PartialEq, Eq, Debug, Hash)]
55#[repr(u8)]
56pub enum IntentScope {
57 TransactionData = 0, TransactionEffects = 1, CheckpointSummary = 2, PersonalMessage = 3, SenderSignedTransaction = 4, ProofOfPossession = 5, HeaderDigest = 6, BridgeEventUnused = 7, ConsensusBlock = 8, }
67
68impl TryFrom<u8> for IntentScope {
69 type Error = eyre::Report;
70 fn try_from(value: u8) -> Result<Self, Self::Error> {
71 bcs::from_bytes(&[value]).map_err(|_| eyre!("Invalid IntentScope"))
72 }
73}
74
75#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone, Hash)]
81pub struct Intent {
82 pub scope: IntentScope,
83 pub version: IntentVersion,
84 pub app_id: AppId,
85}
86
87impl FromStr for Intent {
88 type Err = eyre::Report;
89 fn from_str(s: &str) -> Result<Self, Self::Err> {
90 let s: Vec<u8> = decode_bytes_hex(s).map_err(|_| eyre!("Invalid Intent"))?;
91 if s.len() != 3 {
92 return Err(eyre!("Invalid Intent"));
93 }
94 Ok(Self {
95 scope: s[0].try_into()?,
96 version: s[1].try_into()?,
97 app_id: s[2].try_into()?,
98 })
99 }
100}
101
102impl Intent {
103 pub const fn sui_app(scope: IntentScope) -> Self {
104 Self {
105 version: IntentVersion::V0,
106 scope,
107 app_id: AppId::Sui,
108 }
109 }
110
111 pub const fn sui_transaction() -> Self {
112 Self {
113 scope: IntentScope::TransactionData,
114 version: IntentVersion::V0,
115 app_id: AppId::Sui,
116 }
117 }
118
119 pub const fn personal_message() -> Self {
120 Self {
121 scope: IntentScope::PersonalMessage,
122 version: IntentVersion::V0,
123 app_id: AppId::Sui,
124 }
125 }
126
127 pub const fn narwhal_app(scope: IntentScope) -> Self {
128 Self {
129 scope,
130 version: IntentVersion::V0,
131 app_id: AppId::Narwhal,
132 }
133 }
134
135 pub const fn consensus_app(scope: IntentScope) -> Self {
136 Self {
137 scope,
138 version: IntentVersion::V0,
139 app_id: AppId::Consensus,
140 }
141 }
142}
143
144#[derive(Debug, PartialEq, Eq, Serialize, Clone, Hash, Deserialize)]
153pub struct IntentMessage<T> {
154 pub intent: Intent,
155 pub value: T,
156}
157
158impl<T> IntentMessage<T> {
159 pub const fn new(intent: Intent, value: T) -> Self {
160 Self { intent, value }
161 }
162}