Skip to content

Commit 7ce1cd2

Browse files
authored
add: Plutus data formats used by the bridge (#978)
1 parent 017409b commit 7ce1cd2

File tree

2 files changed

+172
-0
lines changed

2 files changed

+172
-0
lines changed
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
//! Plutus data types used by the token bridge
2+
3+
use crate::*;
4+
use cardano_serialization_lib::{PlutusData, traits::NoneOrEmpty};
5+
use sidechain_domain::byte_string::ByteString;
6+
7+
/// Datum containing token transfer data
8+
#[derive(Clone, Debug, PartialEq)]
9+
pub enum TokenTransferDatum {
10+
/// Version 1
11+
V1(TokenTransferDatumV1),
12+
}
13+
14+
/// Datum containing token transfer data, version 1
15+
#[derive(Clone, Debug, PartialEq)]
16+
pub enum TokenTransferDatumV1 {
17+
/// User-initiated transfer sent to a specific receiver address
18+
UserTransfer {
19+
/// Receiving address on the Partner Chain
20+
receiver: ByteString,
21+
},
22+
/// Reserve transfer
23+
ReserveTransfer,
24+
}
25+
26+
impl From<TokenTransferDatumV1> for PlutusData {
27+
fn from(datum: TokenTransferDatumV1) -> Self {
28+
VersionedGenericDatum {
29+
version: 1,
30+
datum: PlutusData::new_empty_constr_plutus_data(&0u64.into()),
31+
appendix: {
32+
match datum {
33+
TokenTransferDatumV1::UserTransfer { receiver } => {
34+
PlutusData::new_single_value_constr_plutus_data(
35+
&0u64.into(),
36+
&PlutusData::new_bytes(receiver.0),
37+
)
38+
},
39+
TokenTransferDatumV1::ReserveTransfer => {
40+
PlutusData::new_empty_constr_plutus_data(&1u64.into())
41+
},
42+
}
43+
},
44+
}
45+
.into()
46+
}
47+
}
48+
49+
impl From<TokenTransferDatum> for PlutusData {
50+
fn from(datum: TokenTransferDatum) -> Self {
51+
match datum {
52+
TokenTransferDatum::V1(datum) => datum.into(),
53+
}
54+
}
55+
}
56+
57+
impl TryFrom<PlutusData> for TokenTransferDatum {
58+
type Error = DataDecodingError;
59+
fn try_from(data: PlutusData) -> Result<Self, Self::Error> {
60+
Self::decode(&data)
61+
}
62+
}
63+
64+
impl VersionedDatum for TokenTransferDatum {
65+
fn decode(data: &PlutusData) -> crate::DecodingResult<Self> {
66+
match plutus_data_version_and_payload(data) {
67+
None => Err(decoding_error_and_log(data, "TokenTransferDatum", "unversioned datum")),
68+
Some(VersionedGenericDatum { appendix, version: 1, .. }) => {
69+
decode_v1_token_transfer_datum(&appendix).ok_or_else(|| {
70+
decoding_error_and_log(&appendix, "TokenTransferDatum", "malformed appendix")
71+
})
72+
},
73+
Some(_) => Err(decoding_error_and_log(data, "TokenTransferDatum", "invalid version")),
74+
}
75+
}
76+
}
77+
78+
fn decode_v1_token_transfer_datum(appendix: &PlutusData) -> Option<TokenTransferDatum> {
79+
println!(">> {appendix:?}");
80+
let constr = appendix.as_constr_plutus_data()?;
81+
let alternative = u64::from(constr.alternative());
82+
let data = constr.data();
83+
84+
match alternative {
85+
0 if data.len() == 1 => {
86+
let receiver = data.get(0).as_bytes()?.into();
87+
Some(TokenTransferDatum::V1(TokenTransferDatumV1::UserTransfer { receiver }))
88+
},
89+
1 if data.is_none_or_empty() => {
90+
Some(TokenTransferDatum::V1(TokenTransferDatumV1::ReserveTransfer))
91+
},
92+
_ => None,
93+
}
94+
}
95+
96+
#[cfg(test)]
97+
mod tests {
98+
use super::*;
99+
use crate::test_helpers::test_plutus_data;
100+
101+
fn reserve_transfer_data() -> PlutusData {
102+
test_plutus_data!({
103+
"list": [
104+
{ "constructor": 0, "fields": [] },
105+
{ "constructor": 1, "fields": [] },
106+
{ "int":1 },
107+
108+
]
109+
})
110+
}
111+
112+
fn user_transfer_data(addr: &[u8]) -> PlutusData {
113+
test_plutus_data!({
114+
"list": [
115+
{ "constructor": 0, "fields": [] },
116+
{ "constructor": 0, "fields": [{ "bytes": hex::encode(addr) }] },
117+
{ "int":1 },
118+
119+
]
120+
})
121+
}
122+
123+
mod decode {
124+
use super::*;
125+
use hex_literal::hex;
126+
use pretty_assertions::assert_eq;
127+
128+
#[test]
129+
fn user_transfer_v1() {
130+
let datum = TokenTransferDatum::decode(&user_transfer_data(&hex!("abcd")))
131+
.expect("Should decode successfully");
132+
assert_eq!(
133+
datum,
134+
TokenTransferDatum::V1(TokenTransferDatumV1::UserTransfer {
135+
receiver: ByteString(hex!("abcd").into())
136+
})
137+
)
138+
}
139+
140+
#[test]
141+
fn reserve_transfer_v1() {
142+
let datum = TokenTransferDatum::decode(&reserve_transfer_data())
143+
.expect("Should decode successfully");
144+
assert_eq!(datum, TokenTransferDatum::V1(TokenTransferDatumV1::ReserveTransfer))
145+
}
146+
}
147+
148+
mod encode {
149+
use super::*;
150+
use hex_literal::hex;
151+
use pretty_assertions::assert_eq;
152+
153+
#[test]
154+
fn user_transfer_v1() {
155+
let data: PlutusData = TokenTransferDatum::V1(TokenTransferDatumV1::UserTransfer {
156+
receiver: ByteString::from_hex_unsafe("abcd"),
157+
})
158+
.into();
159+
160+
assert_eq!(data, user_transfer_data(&hex!("abcd")))
161+
}
162+
163+
#[test]
164+
fn reserve_transfer_v1() {
165+
let data: PlutusData =
166+
TokenTransferDatum::V1(TokenTransferDatumV1::ReserveTransfer).into();
167+
168+
assert_eq!(data, reserve_transfer_data())
169+
}
170+
}
171+
}

toolkit/smart-contracts/plutus-data/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#![deny(missing_docs)]
33
use cardano_serialization_lib::{PlutusData, PlutusList};
44

5+
pub mod bridge;
56
pub mod candidate_keys;
67
pub mod d_param;
78
pub mod governed_map;

0 commit comments

Comments
 (0)