From aa97e029620f227650bca7395626a972935aaf60 Mon Sep 17 00:00:00 2001 From: Armando Dutra Date: Mon, 7 Aug 2023 21:26:21 -0300 Subject: [PATCH 1/2] feat: import contract armored --- Cargo.lock | 10 ++++++ Cargo.toml | 1 + src/rgb/contract.rs | 1 + src/rgb/import.rs | 57 ++++++++++++++++++++++++--------- src/rgb/prefetch.rs | 24 +++----------- tests/rgb/integration/import.rs | 19 +++++++++++ 6 files changed, 76 insertions(+), 36 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e7549e42..0d7eb20c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -393,6 +393,15 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "base85" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36915bbaca237c626689b5bd14d02f2ba7a5a359d30a2a08be697392e3718079" +dependencies = [ + "thiserror", +] + [[package]] name = "bdk" version = "0.28.0" @@ -588,6 +597,7 @@ dependencies = [ "axum", "axum-macros", "base64-compat", + "base85", "bdk", "bech32", "bip39", diff --git a/Cargo.toml b/Cargo.toml index a78f561c..14771d26 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -86,6 +86,7 @@ thiserror = "1.0" tokio = { version = "1.28.2", features = ["macros", "sync"] } zeroize = "1.6.0" blake3 = "1.4.1" +base85 = "2.0.0" [target.'cfg(target_arch = "wasm32")'.dependencies] bdk = { version = "0.28.0", features = [ diff --git a/src/rgb/contract.rs b/src/rgb/contract.rs index b1687012..1f67eb27 100644 --- a/src/rgb/contract.rs +++ b/src/rgb/contract.rs @@ -103,6 +103,7 @@ where )) } }; + let genesis_strict = genesis_serialized.to_hex(); let genesis_legacy = match encode( "rgb", diff --git a/src/rgb/import.rs b/src/rgb/import.rs index 9b268458..697396d9 100644 --- a/src/rgb/import.rs +++ b/src/rgb/import.rs @@ -1,3 +1,5 @@ +use std::str::FromStr; + use amplify::{ confinement::{Confined, U32}, hex::FromHex, @@ -5,7 +7,7 @@ use amplify::{ use bech32::{decode, FromBase32}; use rgb_schemata::{nia_rgb20, nia_schema, uda_rgb21, uda_schema}; use rgbstd::{ - containers::Contract, + containers::{Bindle, Contract}, contract::Genesis, interface::{rgb20, rgb21, IfacePair}, persistence::{Inventory, Stash, Stock}, @@ -31,22 +33,10 @@ where R: ResolveHeight + ResolveTx, R::Error: 'static, { - let serialized = if contract.starts_with("rgb1") { - let (_, serialized, _) = - decode(contract).expect("invalid serialized contract (bech32m format)"); - Vec::::from_base32(&serialized).expect("invalid hexadecimal contract (bech32m format)") + let contract = if contract.starts_with("-----BEGIN RGB CONTRACT-----") { + contract_from_armored(contract) } else { - Vec::::from_hex(contract).expect("invalid hexadecimal contract (baid58 format)") - }; - - let confined: Confined, 0, { U32 }> = - Confined::try_from_iter(serialized.iter().copied()) - .expect("invalid strict serialized data"); - - let contract = match Genesis::from_strict_serialized::<{ U32 }>(confined.clone()) { - Ok(genesis) => contract_from_genesis(genesis, asset_type, Some(stock)), - Err(_) => Contract::from_strict_serialized::<{ U32 }>(confined) - .expect("invalid strict contract data"), + contract_from_other_formats(contract, Some(asset_type), Some(stock)) }; let contract_id = contract.contract_id(); @@ -65,6 +55,41 @@ where Ok(contract) } +pub fn contract_from_armored(contract: &str) -> Contract { + Bindle::::from_str(contract) + .expect("invalid serialized contract/genesis (base58 format)") + .unbindle() +} + +pub fn contract_from_other_formats( + contract: &str, + asset_type: Option, + stock: Option<&mut Stock>, +) -> Contract { + let serialized = if contract.starts_with("rgb1") { + let (_, serialized, _) = + decode(contract).expect("invalid serialized contract/genesis (bech32m format)"); + Vec::::from_base32(&serialized) + .expect("invalid hexadecimal contract/genesis (bech32m format)") + } else { + Vec::::from_hex(contract).expect("invalid hexadecimal contract/genesis") + }; + + let confined: Confined, 0, { U32 }> = + Confined::try_from_iter(serialized.iter().copied()) + .expect("invalid strict serialized data"); + + match asset_type { + Some(asset_type) => { + let genesis = Genesis::from_strict_serialized::<{ U32 }>(confined) + .expect("invalid strict genesis data"); + contract_from_genesis(genesis, asset_type, stock) + } + None => Contract::from_strict_serialized::<{ U32 }>(confined) + .expect("invalid strict contract data"), + } +} + pub fn contract_from_genesis( genesis: Genesis, asset_type: AssetType, diff --git a/src/rgb/prefetch.rs b/src/rgb/prefetch.rs index e71425ef..55743934 100644 --- a/src/rgb/prefetch.rs +++ b/src/rgb/prefetch.rs @@ -91,32 +91,16 @@ pub async fn prefetch_resolver_rgb( explorer: &mut ExplorerResolver, asset_type: Option, ) { - use crate::rgb::import::contract_from_genesis; + use crate::rgb::import::{contract_from_armored, contract_from_other_formats}; use amplify::confinement::U32; use rgbstd::contract::Genesis; let esplora_client: EsploraBlockchain = EsploraBlockchain::new(&explorer.explorer_url, 1).with_concurrency(6); - let serialized = if contract.starts_with("rgb1") { - let (_, serialized, _) = - decode(contract).expect("invalid serialized contract (bech32m format)"); - Vec::::from_base32(&serialized).expect("invalid hexadecimal contract (bech32m format)") + let contract = if contract.starts_with("-----BEGIN RGB CONTRACT-----") { + contract_from_armored(contract) } else { - Vec::::from_hex(contract).expect("invalid hexadecimal contract (baid58 format)") - }; - - let confined: Confined, 0, { U32 }> = - Confined::try_from_iter(serialized.iter().copied()) - .expect("invalid strict serialized data"); - - let contract = match asset_type { - Some(asset_type) => match Genesis::from_strict_serialized::<{ U32 }>(confined.clone()) { - Ok(genesis) => contract_from_genesis(genesis, asset_type, None), - Err(_) => Contract::from_strict_serialized::<{ U32 }>(confined) - .expect("invalid strict contract data"), - }, - _ => Contract::from_strict_serialized::<{ U32 }>(confined) - .expect("invalid strict contract data"), + contract_from_other_formats(contract, asset_type, None) }; for anchor_bundle in contract.bundles { diff --git a/tests/rgb/integration/import.rs b/tests/rgb/integration/import.rs index 1d7e5ee1..43b18312 100644 --- a/tests/rgb/integration/import.rs +++ b/tests/rgb/integration/import.rs @@ -25,6 +25,25 @@ async fn allow_import_fungibles_from_genesis() -> anyhow::Result<()> { Ok(()) } +#[tokio::test] +async fn allow_import_fungibles_from_contract() -> anyhow::Result<()> { + let issuer_resp = issuer_issue_contract("RGB20", 5, false, true, None).await; + assert!(issuer_resp.is_ok()); + + let another_vault = new_mnemonic(&SecretString("".to_string())).await?; + + let sk = &another_vault.private.nostr_prv; + let contract_import = ImportRequest { + import: AssetType::RGB20, + data: issuer_resp?.contract.armored, + }; + + let import_resp = import(sk, contract_import).await; + assert!(import_resp.is_ok()); + + Ok(()) +} + #[tokio::test] async fn allow_import_fungibles_from_genesis_data() -> anyhow::Result<()> { let issuer_keys = save_mnemonic( From e1ac176e2a844fbc707c36e5a9ff975edf1a9a9e Mon Sep 17 00:00:00 2001 From: Armando Dutra Date: Mon, 7 Aug 2023 21:43:13 -0300 Subject: [PATCH 2/2] fix: import genesis --- src/rgb/import.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/rgb/import.rs b/src/rgb/import.rs index 697396d9..429c2c69 100644 --- a/src/rgb/import.rs +++ b/src/rgb/import.rs @@ -80,11 +80,11 @@ pub fn contract_from_other_formats( .expect("invalid strict serialized data"); match asset_type { - Some(asset_type) => { - let genesis = Genesis::from_strict_serialized::<{ U32 }>(confined) - .expect("invalid strict genesis data"); - contract_from_genesis(genesis, asset_type, stock) - } + Some(asset_type) => match Genesis::from_strict_serialized::<{ U32 }>(confined.clone()) { + Ok(genesis) => contract_from_genesis(genesis, asset_type, stock), + Err(_) => Contract::from_strict_serialized::<{ U32 }>(confined) + .expect("invalid strict contract data"), + }, None => Contract::from_strict_serialized::<{ U32 }>(confined) .expect("invalid strict contract data"), }