Skip to content

Commit

Permalink
WASM: expose the Asset and AssetIdentifier types
Browse files Browse the repository at this point in the history
  • Loading branch information
andiflabs committed Nov 14, 2024
1 parent c18f4d4 commit 13a7675
Show file tree
Hide file tree
Showing 4 changed files with 238 additions and 2 deletions.
233 changes: 233 additions & 0 deletions ironfish-rust-wasm/src/assets.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::{
errors::IronfishError,
keys::PublicAddress,
primitives::{ExtendedPoint, SubgroupPoint},
};
use ironfish::errors::IronfishErrorKind;
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Asset(ironfish::assets::asset::Asset);

#[wasm_bindgen]
impl Asset {
#[wasm_bindgen(constructor)]
pub fn deserialize(bytes: &[u8]) -> Result<Asset, IronfishError> {
Ok(Self(ironfish::assets::asset::Asset::read(bytes)?))
}

#[wasm_bindgen]
pub fn serialize(&self) -> Vec<u8> {
let mut buf = Vec::new();
self.0.write(&mut buf).expect("failed to serialize asset");
buf
}

#[wasm_bindgen(js_name = fromParts)]
pub fn from_parts(
creator: PublicAddress,
name: &str,
metadata: &str,
) -> Result<Self, IronfishError> {
Ok(Self(ironfish::assets::asset::Asset::new(
creator.as_ref().to_owned(),
name,
metadata,
)?))
}

#[wasm_bindgen(js_name = fromPartsWithNonce)]
pub fn from_parts_with_nonce(
creator: PublicAddress,
name: &[u8],
metadata: &[u8],
nonce: u8,
) -> Result<Self, IronfishError> {
let name = name
.try_into()
.map_err(|_| IronfishErrorKind::InvalidData)?;
let metadata = metadata
.try_into()
.map_err(|_| IronfishErrorKind::InvalidData)?;
Ok(Self(ironfish::assets::asset::Asset::new_with_nonce(
creator.as_ref().to_owned(),
name,
metadata,
nonce,
)?))
}

#[wasm_bindgen(getter)]
pub fn metadata(&self) -> Vec<u8> {
self.0.metadata().to_vec()
}

#[wasm_bindgen(getter)]
pub fn name(&self) -> Vec<u8> {
self.0.name().to_vec()
}

#[wasm_bindgen(getter)]
pub fn nonce(&self) -> u8 {
self.0.nonce()
}

#[wasm_bindgen(getter)]
pub fn creator(&self) -> PublicAddress {
PublicAddress::deserialize(self.0.creator().as_slice())
.expect("failed to deserialize public address")
}

#[wasm_bindgen(getter)]
pub fn id(&self) -> AssetIdentifier {
self.0.id().to_owned().into()
}

#[wasm_bindgen(getter, js_name = assetGenerator)]
pub fn asset_generator(&self) -> ExtendedPoint {
self.0.asset_generator().into()
}

#[wasm_bindgen(getter, js_name = valueCommitmentGenerator)]
pub fn value_commitment_generator(&self) -> SubgroupPoint {
self.0.value_commitment_generator().into()
}
}

impl From<ironfish::assets::asset::Asset> for Asset {
fn from(d: ironfish::assets::asset::Asset) -> Self {
Self(d)
}
}

impl AsRef<ironfish::assets::asset::Asset> for Asset {
fn as_ref(&self) -> &ironfish::assets::asset::Asset {
&self.0
}
}

#[wasm_bindgen]
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct AssetIdentifier(ironfish::assets::asset_identifier::AssetIdentifier);

#[wasm_bindgen]
impl AssetIdentifier {
#[wasm_bindgen(constructor)]
pub fn deserialize(bytes: &[u8]) -> Result<AssetIdentifier, IronfishError> {
Ok(Self(
ironfish::assets::asset_identifier::AssetIdentifier::read(bytes)?,
))
}

#[wasm_bindgen]
pub fn serialize(&self) -> Vec<u8> {
self.0.as_bytes().to_vec()
}

#[wasm_bindgen(getter, js_name = assetGenerator)]
pub fn asset_generator(&self) -> ExtendedPoint {
self.0.asset_generator().into()
}

#[wasm_bindgen(getter, js_name = valueCommitmentGenerator)]
pub fn value_commitment_generator(&self) -> SubgroupPoint {
self.0.value_commitment_generator().into()
}
}

impl From<ironfish::assets::asset_identifier::AssetIdentifier> for AssetIdentifier {
fn from(d: ironfish::assets::asset_identifier::AssetIdentifier) -> Self {
Self(d)
}
}

impl AsRef<ironfish::assets::asset_identifier::AssetIdentifier> for AssetIdentifier {
fn as_ref(&self) -> &ironfish::assets::asset_identifier::AssetIdentifier {
&self.0
}
}

#[cfg(test)]
mod tests {
mod asset {
use crate::{assets::Asset, keys::PublicAddress};
use hex_literal::hex;
use wasm_bindgen_test::wasm_bindgen_test;

fn test_address() -> PublicAddress {
PublicAddress::deserialize(
hex!("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0").as_slice(),
)
.unwrap()
}

fn test_asset() -> Asset {
let asset = Asset::from_parts(test_address(), "name", "meta").unwrap();

assert_eq!(asset.creator(), test_address());
assert_eq!(
asset.name(),
b"name\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
);
assert_eq!(
asset.metadata(),
b"meta\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0"
);
assert_eq!(
asset.id().serialize(),
hex!("2b845f8f97b90d2279bf502eb3ebdf71bf47460b083ca926421b0c7ee68ec816")
);

asset
}

#[test]
#[wasm_bindgen_test]
fn serialize_deserialize_roundtrip() {
let asset = test_asset();

let serialization = asset.serialize();
let deserialized = Asset::deserialize(&serialization[..]).unwrap();

assert_eq!(asset, deserialized);
assert_eq!(serialization, deserialized.serialize());
}

#[test]
#[wasm_bindgen_test]
fn from_parts_with_nonce() {
let asset = Asset::from_parts_with_nonce(
test_address(),
b"name\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
b"meta\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0",
0,
)
.unwrap();
assert_eq!(asset, test_asset());
}
}

mod asset_identifier {
use crate::assets::AssetIdentifier;
use hex_literal::hex;
use wasm_bindgen_test::wasm_bindgen_test;

#[test]
#[wasm_bindgen_test]
fn serialize_deserialize_roundtrip() {
let serialization =
hex!("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb1");
let id = AssetIdentifier::deserialize(&serialization[..]).unwrap();
assert_eq!(id.serialize(), serialization);
}
}
}
4 changes: 3 additions & 1 deletion ironfish-rust-wasm/src/keys/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */

pub mod public_address;
mod public_address;

pub use public_address::PublicAddress;
1 change: 1 addition & 0 deletions ironfish-rust-wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
// The getrandom dependency exists only to ensure that the `js` feature is enabled
use getrandom as _;

pub mod assets;
pub mod errors;
pub mod keys;
pub mod primitives;
Expand Down
2 changes: 1 addition & 1 deletion ironfish-rust/src/assets/asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub const ID_LENGTH: usize = ASSET_ID_LENGTH;

/// Describes all the fields necessary for creating and transacting with an
/// asset on the Iron Fish network
#[derive(Clone, Copy, PartialEq, Debug)]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Asset {
/// Name of the asset
pub(crate) name: [u8; NAME_LENGTH],
Expand Down

0 comments on commit 13a7675

Please sign in to comment.