Skip to content

Commit cac56c5

Browse files
authored
Merge pull request #615 from Emurgo/evgenii/address2datum
Address to plutus datum conversion
2 parents e72cd6f + 65650a8 commit cac56c5

File tree

4 files changed

+203
-43
lines changed

4 files changed

+203
-43
lines changed

rust/pkg/cardano_serialization_lib.js.flow

Lines changed: 56 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,26 @@
55
* @flow
66
*/
77

8+
/**
9+
* @param {string} json
10+
* @param {number} schema
11+
* @returns {PlutusData}
12+
*/
13+
declare export function encode_json_str_to_plutus_datum(
14+
json: string,
15+
schema: number
16+
): PlutusData;
17+
18+
/**
19+
* @param {PlutusData} datum
20+
* @param {number} schema
21+
* @returns {string}
22+
*/
23+
declare export function decode_plutus_datum_to_json_str(
24+
datum: PlutusData,
25+
schema: number
26+
): string;
27+
828
/**
929
* @param {Uint8Array} bytes
1030
* @returns {TransactionMetadatum}
@@ -41,26 +61,6 @@ declare export function decode_metadatum_to_json_str(
4161
schema: number
4262
): string;
4363

44-
/**
45-
* @param {string} json
46-
* @param {number} schema
47-
* @returns {PlutusData}
48-
*/
49-
declare export function encode_json_str_to_plutus_datum(
50-
json: string,
51-
schema: number
52-
): PlutusData;
53-
54-
/**
55-
* @param {PlutusData} datum
56-
* @param {number} schema
57-
* @returns {string}
58-
*/
59-
declare export function decode_plutus_datum_to_json_str(
60-
datum: PlutusData,
61-
schema: number
62-
): string;
63-
6464
/**
6565
* @param {Transaction} tx
6666
* @param {LinearFee} linear_fee
@@ -333,26 +333,6 @@ declare export var NetworkIdKind: {|
333333
+Mainnet: 1, // 1
334334
|};
335335

336-
/**
337-
*/
338-
339-
declare export var TransactionMetadatumKind: {|
340-
+MetadataMap: 0, // 0
341-
+MetadataList: 1, // 1
342-
+Int: 2, // 2
343-
+Bytes: 3, // 3
344-
+Text: 4, // 4
345-
|};
346-
347-
/**
348-
*/
349-
350-
declare export var MetadataJsonSchema: {|
351-
+NoConversions: 0, // 0
352-
+BasicConversions: 1, // 1
353-
+DetailedSchema: 2, // 2
354-
|};
355-
356336
/**
357337
*/
358338

@@ -399,6 +379,26 @@ declare export var PlutusDatumSchema: {|
399379
+DetailedSchema: 1, // 1
400380
|};
401381

382+
/**
383+
*/
384+
385+
declare export var TransactionMetadatumKind: {|
386+
+MetadataMap: 0, // 0
387+
+MetadataList: 1, // 1
388+
+Int: 2, // 2
389+
+Bytes: 3, // 3
390+
+Text: 4, // 4
391+
|};
392+
393+
/**
394+
*/
395+
396+
declare export var MetadataJsonSchema: {|
397+
+NoConversions: 0, // 0
398+
+BasicConversions: 1, // 1
399+
+DetailedSchema: 2, // 2
400+
|};
401+
402402
/**
403403
*/
404404

@@ -4729,6 +4729,16 @@ declare export class PlutusData {
47294729
*/
47304730
static new_empty_constr_plutus_data(alternative: BigNum): PlutusData;
47314731

4732+
/**
4733+
* @param {BigNum} alternative
4734+
* @param {PlutusData} plutus_data
4735+
* @returns {PlutusData}
4736+
*/
4737+
static new_single_value_constr_plutus_data(
4738+
alternative: BigNum,
4739+
plutus_data: PlutusData
4740+
): PlutusData;
4741+
47324742
/**
47334743
* @param {PlutusMap} map
47344744
* @returns {PlutusData}
@@ -4795,6 +4805,12 @@ declare export class PlutusData {
47954805
* @returns {PlutusData}
47964806
*/
47974807
static from_json(json: string, schema: number): PlutusData;
4808+
4809+
/**
4810+
* @param {Address} address
4811+
* @returns {PlutusData}
4812+
*/
4813+
static from_address(address: Address): PlutusData;
47984814
}
47994815
/**
48004816
*/

rust/src/address.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ pub enum StakeCredKind {
120120
serde::Deserialize,
121121
JsonSchema,
122122
)]
123-
pub struct StakeCredential(StakeCredType);
123+
pub struct StakeCredential(pub(crate) StakeCredType);
124124

125125
#[wasm_bindgen]
126126
impl StakeCredential {
@@ -220,7 +220,7 @@ impl Deserialize for StakeCredential {
220220
}
221221

222222
#[derive(Debug, Clone, Eq, Ord, PartialEq, PartialOrd)]
223-
enum AddrType {
223+
pub(crate) enum AddrType {
224224
Base(BaseAddress),
225225
Ptr(PointerAddress),
226226
Enterprise(EnterpriseAddress),
@@ -336,7 +336,7 @@ impl ByronAddress {
336336

337337
#[wasm_bindgen]
338338
#[derive(Debug, Clone, Eq, Ord, PartialEq, PartialOrd)]
339-
pub struct Address(AddrType);
339+
pub struct Address(pub(crate) AddrType);
340340

341341
from_bytes!(Address, data, { Self::from_bytes_impl(data.as_ref()) });
342342

rust/src/plutus.rs

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,12 @@ impl PlutusData {
648648
Self::new_constr_plutus_data(&ConstrPlutusData::new(alternative, &PlutusList::new()))
649649
}
650650

651+
pub fn new_single_value_constr_plutus_data(alternative: &BigNum, plutus_data: &PlutusData) -> Self {
652+
let mut list = PlutusList::new();
653+
list.add(plutus_data);
654+
Self::new_constr_plutus_data(&ConstrPlutusData::new(alternative, &list))
655+
}
656+
651657
pub fn new_map(map: &PlutusMap) -> Self {
652658
Self {
653659
datum: PlutusDataEnum::Map(map.clone()),
@@ -728,6 +734,82 @@ impl PlutusData {
728734
pub fn from_json(json: &str, schema: PlutusDatumSchema) -> Result<PlutusData, JsError> {
729735
encode_json_str_to_plutus_datum(json, schema)
730736
}
737+
738+
pub fn from_address(address: &Address) -> Result<PlutusData, JsError> {
739+
let payment_cred = match &address.0 {
740+
AddrType::Base(addr) => Ok(addr.payment_cred()),
741+
AddrType::Enterprise(addr) => Ok(addr.payment_cred()),
742+
AddrType::Ptr(addr) => Ok(addr.payment_cred()),
743+
AddrType::Reward(addr) => Ok(addr.payment_cred()),
744+
AddrType::Byron(_) =>
745+
Err(JsError::from_str("Cannot convert Byron address to PlutusData")),
746+
}?;
747+
748+
let staking_data = match &address.0 {
749+
AddrType::Base(addr) => {
750+
let staking_bytes_data =
751+
PlutusData::from_stake_credential(&addr.stake_cred())?;
752+
Some(PlutusData::new_single_value_constr_plutus_data(
753+
&BigNum::from(0u32),
754+
&staking_bytes_data,
755+
))
756+
}
757+
_ => None,
758+
};
759+
760+
let pointer_data = match &address.0 {
761+
AddrType::Ptr(addr) =>
762+
Some(PlutusData::from_pointer(&addr.stake_pointer())?),
763+
_ => None,
764+
};
765+
766+
let payment_data = PlutusData::from_stake_credential(&payment_cred)?;
767+
let staking_optional_data = match (staking_data, pointer_data) {
768+
(Some(_), Some(_)) =>
769+
Err(JsError::from_str("Address can't have both staking and pointer data")),
770+
(Some(staking_data), None) => Ok(Some(staking_data)),
771+
(None, Some(pointer_data)) => Ok(Some(pointer_data)),
772+
(None, None) => Ok(None)
773+
}?;
774+
775+
let mut data_list = PlutusList::new();
776+
data_list.add(&payment_data);
777+
if let Some(staking_optional_data) = staking_optional_data {
778+
data_list.add(
779+
&PlutusData::new_single_value_constr_plutus_data(
780+
&BigNum::from(0u32), &staking_optional_data));
781+
} else {
782+
data_list.add(&PlutusData::new_empty_constr_plutus_data(
783+
&BigNum::from(1u32)));
784+
}
785+
786+
787+
Ok(PlutusData::new_constr_plutus_data(&ConstrPlutusData::new(
788+
&BigNum::from(0u32),
789+
&data_list,
790+
)))
791+
}
792+
793+
fn from_stake_credential(stake_credential: &StakeCredential) -> Result<PlutusData, JsError> {
794+
let (bytes_plutus_data, index) = match &stake_credential.0 {
795+
StakeCredType::Key(key_hash) =>
796+
(PlutusData::new_bytes(key_hash.to_bytes().to_vec()), BigNum::from(0u32)),
797+
StakeCredType::Script(script_hash) =>
798+
(PlutusData::new_bytes(script_hash.to_bytes().to_vec()), BigNum::from(1u32)),
799+
};
800+
801+
Ok(PlutusData::new_single_value_constr_plutus_data(&index, &bytes_plutus_data))
802+
}
803+
804+
fn from_pointer(pointer: &Pointer) -> Result<PlutusData, JsError> {
805+
let mut data_list = PlutusList::new();
806+
data_list.add(&PlutusData::new_integer(&pointer.slot_bignum().into()));
807+
data_list.add(&PlutusData::new_integer(&pointer.tx_index_bignum().into()));
808+
data_list.add(&PlutusData::new_integer(&pointer.cert_index_bignum().into()));
809+
810+
Ok(PlutusData::new_constr_plutus_data(
811+
&ConstrPlutusData::new(&BigNum::from(1u32), &data_list)))
812+
}
731813
}
732814

733815
//TODO: replace this by cardano-node schemas
@@ -2443,4 +2525,58 @@ mod tests {
24432525
);
24442526
assert_eq!(hex::encode(hash.to_bytes()), "0a076247a05aacbecf72ea15b94e3d0331b21295a08d9ab7b8675c13840563a6");
24452527
}
2528+
2529+
#[test]
2530+
fn datum_from_enterprise_key_address() {
2531+
let address = Address::from_bech32("addr1vxy2c673nsdp0mvgq5d3tpjndngucsytug00k7k6xwlx4lg6dspk5").unwrap();
2532+
let datum = PlutusData::from_address(&address).unwrap();
2533+
let orig_datum = PlutusData::from_json("{\"constructor\": 0, \"fields\": [{\"constructor\": 0, \"fields\": [{\"bytes\": \"88ac6bd19c1a17ed88051b1586536cd1cc408be21efb7ada33be6afd\"}]}, {\"constructor\": 1, \"fields\": []}]}",
2534+
PlutusDatumSchema::DetailedSchema).unwrap();
2535+
assert_eq!(datum, orig_datum);
2536+
}
2537+
2538+
#[test]
2539+
fn datum_from_enterprise_script_address() {
2540+
let address = Address::from_bech32("addr1w8wrk560wcsldjpnqjamn8s0gn9pdrplpyetrdfpacqrpfs3xezd8").unwrap();
2541+
let datum = PlutusData::from_address(&address).unwrap();
2542+
let orig_datum = PlutusData::from_json("{\"constructor\": 0, \"fields\": [{\"constructor\": 1, \"fields\": [{\"bytes\": \"dc3b534f7621f6c83304bbb99e0f44ca168c3f0932b1b521ee0030a6\"}]}, {\"constructor\": 1, \"fields\": []}]}",
2543+
PlutusDatumSchema::DetailedSchema).unwrap();
2544+
assert_eq!(datum, orig_datum);
2545+
}
2546+
2547+
#[test]
2548+
fn datum_from_base_key_key_address() {
2549+
let address = Address::from_bech32("addr1qxy2c673nsdp0mvgq5d3tpjndngucsytug00k7k6xwlx4lvg434ar8q6zlkcspgmzkr9xmx3e3qghcs7ldad5va7dt7s5efyer").unwrap();
2550+
let datum = PlutusData::from_address(&address).unwrap();
2551+
let orig_datum = PlutusData::from_json("{\"constructor\": 0, \"fields\": [{\"constructor\": 0, \"fields\": [{\"bytes\": \"88ac6bd19c1a17ed88051b1586536cd1cc408be21efb7ada33be6afd\"}]}, {\"constructor\": 0, \"fields\": [{\"constructor\": 0, \"fields\": [{\"constructor\": 0, \"fields\": [{\"bytes\": \"88ac6bd19c1a17ed88051b1586536cd1cc408be21efb7ada33be6afd\"}]}]}]}]}",
2552+
PlutusDatumSchema::DetailedSchema).unwrap();
2553+
assert_eq!(datum, orig_datum);
2554+
}
2555+
2556+
#[test]
2557+
fn datum_from_base_script_script_address() {
2558+
let address = Address::from_bech32("addr1x8wrk560wcsldjpnqjamn8s0gn9pdrplpyetrdfpacqrpfku8df57a3p7myrxp9mhx0q73x2z6xr7zfjkx6jrmsqxznqh8u5dz").unwrap();
2559+
let datum = PlutusData::from_address(&address).unwrap();
2560+
let orig_datum = PlutusData::from_json("{\"constructor\": 0, \"fields\": [{\"constructor\": 1, \"fields\": [{\"bytes\": \"dc3b534f7621f6c83304bbb99e0f44ca168c3f0932b1b521ee0030a6\"}]}, {\"constructor\": 0, \"fields\": [{\"constructor\": 0, \"fields\": [{\"constructor\": 1, \"fields\": [{\"bytes\": \"dc3b534f7621f6c83304bbb99e0f44ca168c3f0932b1b521ee0030a6\"}]}]}]}]}",
2561+
PlutusDatumSchema::DetailedSchema).unwrap();
2562+
assert_eq!(datum, orig_datum);
2563+
}
2564+
2565+
#[test]
2566+
fn datum_from_base_script_key_address() {
2567+
let address = Address::from_bech32("addr1z8wrk560wcsldjpnqjamn8s0gn9pdrplpyetrdfpacqrpf5g434ar8q6zlkcspgmzkr9xmx3e3qghcs7ldad5va7dt7sqx2wxh").unwrap();
2568+
let datum = PlutusData::from_address(&address).unwrap();
2569+
let orig_datum = PlutusData::from_json("{\"constructor\": 0, \"fields\": [{\"constructor\": 1, \"fields\": [{\"bytes\": \"dc3b534f7621f6c83304bbb99e0f44ca168c3f0932b1b521ee0030a6\"}]}, {\"constructor\": 0, \"fields\": [{\"constructor\": 0, \"fields\": [{\"constructor\": 0, \"fields\": [{\"bytes\": \"88ac6bd19c1a17ed88051b1586536cd1cc408be21efb7ada33be6afd\"}]}]}]}]}",
2570+
PlutusDatumSchema::DetailedSchema).unwrap();
2571+
assert_eq!(datum, orig_datum);
2572+
}
2573+
2574+
#[test]
2575+
fn datum_from_base_key_script_address() {
2576+
let address = Address::from_bech32("addr1yxy2c673nsdp0mvgq5d3tpjndngucsytug00k7k6xwlx4lwu8df57a3p7myrxp9mhx0q73x2z6xr7zfjkx6jrmsqxznqrcl7jk").unwrap();
2577+
let datum = PlutusData::from_address(&address).unwrap();
2578+
let orig_datum = PlutusData::from_json("{\"constructor\": 0, \"fields\": [{\"constructor\": 0, \"fields\": [{\"bytes\": \"88ac6bd19c1a17ed88051b1586536cd1cc408be21efb7ada33be6afd\"}]}, {\"constructor\": 0, \"fields\": [{\"constructor\": 0, \"fields\": [{\"constructor\": 1, \"fields\": [{\"bytes\": \"dc3b534f7621f6c83304bbb99e0f44ca168c3f0932b1b521ee0030a6\"}]}]}]}]}",
2579+
PlutusDatumSchema::DetailedSchema).unwrap();
2580+
assert_eq!(datum, orig_datum);
2581+
}
24462582
}

rust/src/utils.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,6 +1103,14 @@ impl<T> std::convert::From<T> for BigInt
11031103
}
11041104
}
11051105

1106+
impl From<BigNum> for BigInt
1107+
where
1108+
{
1109+
fn from(x: BigNum) -> Self {
1110+
Self(x.0.into())
1111+
}
1112+
}
1113+
11061114
// we use the cbor_event::Serialize trait directly
11071115

11081116
// This is only for use for plain cddl groups who need to be embedded within outer groups.

0 commit comments

Comments
 (0)