use std::convert::{TryFrom, TryInto};
use ergo_lib::ergotree_ir::chain;
use ergo_lib::ergotree_ir::chain::ergo_box::BoxTokens;
use ergo_lib::ergotree_ir::chain::ergo_box::NonMandatoryRegisters;
use ergo_lib::ergotree_ir::serialization::SigmaSerializable;
use ergo_lib::wallet::tx_builder::new_miner_fee_box;
use gloo_utils::format::JsValueSerdeExt;
use js_sys::Uint8Array;
use wasm_bindgen::prelude::*;
use crate::contract::Contract;
use crate::ergo_tree::ErgoTree;
use crate::error_conversion::to_js;
use crate::json::ErgoBoxJsonEip12;
use crate::token::Tokens;
use crate::utils::I64;
use crate::{ast::Constant, transaction::TxId};
extern crate derive_more;
use derive_more::{From, Into};
pub mod box_builder;
#[wasm_bindgen]
#[derive(PartialEq, Eq, Debug, Clone, From, Into)]
pub struct BoxId(chain::ergo_box::BoxId);
#[wasm_bindgen]
impl BoxId {
#[allow(clippy::should_implement_trait)]
pub fn from_str(box_id_str: String) -> Result<BoxId, JsValue> {
chain::ergo_box::BoxId::try_from(box_id_str)
.map(BoxId)
.map_err(to_js)
}
pub fn to_str(&self) -> String {
self.0.into()
}
pub fn as_bytes(&self) -> Uint8Array {
Uint8Array::from(self.0.as_ref())
}
}
#[wasm_bindgen]
#[derive(PartialEq, Eq, Debug, Clone, From, Into)]
pub struct ErgoBoxCandidate(chain::ergo_box::ErgoBoxCandidate);
#[wasm_bindgen]
impl ErgoBoxCandidate {
pub fn new_miner_fee_box(
fee_amount: &BoxValue,
creation_height: u32,
) -> Result<ErgoBoxCandidate, JsValue> {
Ok(new_miner_fee_box(fee_amount.into(), creation_height)
.map_err(to_js)?
.into())
}
pub fn register_value(
&self,
register_id: NonMandatoryRegisterId,
) -> Result<Option<Constant>, JsValue> {
Ok(self
.0
.additional_registers
.get_constant(register_id.into())
.map_err(to_js)?
.map(Constant::from))
}
pub fn creation_height(&self) -> u32 {
self.0.creation_height
}
pub fn tokens(&self) -> Tokens {
self.0.tokens.clone().into()
}
pub fn ergo_tree(&self) -> ErgoTree {
self.0.ergo_tree.clone().into()
}
pub fn value(&self) -> BoxValue {
self.0.value.into()
}
pub fn serialized_additional_registers(&self) -> Result<Vec<u8>, JsValue> {
self.0
.additional_registers
.sigma_serialize_bytes()
.map_err(|e| JsValue::from_str(&format!("{}", e)))
}
}
#[wasm_bindgen]
#[derive(PartialEq, Eq, Debug, Clone)]
pub struct ErgoBox(chain::ergo_box::ErgoBox);
#[wasm_bindgen]
impl ErgoBox {
#[wasm_bindgen(constructor)]
pub fn new(
value: &BoxValue,
creation_height: u32,
contract: &Contract,
tx_id: &TxId,
index: u16,
tokens: &Tokens,
) -> Result<ErgoBox, JsValue> {
let chain_contract: ergo_lib::chain::contract::Contract = contract.clone().into();
let b = chain::ergo_box::ErgoBox::new(
value.0,
chain_contract.ergo_tree(),
tokens.clone().try_into()?,
NonMandatoryRegisters::empty(),
creation_height,
tx_id.clone().into(),
index,
)
.map_err(to_js)?;
Ok(ErgoBox(b))
}
pub fn box_id(&self) -> BoxId {
self.0.box_id().into()
}
pub fn tx_id(&self) -> TxId {
self.0.transaction_id.into()
}
pub fn index(&self) -> u16 {
self.0.index
}
pub fn creation_height(&self) -> u32 {
self.0.creation_height
}
pub fn tokens(&self) -> Tokens {
self.0.tokens.clone().into()
}
pub fn ergo_tree(&self) -> ErgoTree {
self.0.ergo_tree.clone().into()
}
pub fn value(&self) -> BoxValue {
self.0.value.into()
}
pub fn register_value(
&self,
register_id: NonMandatoryRegisterId,
) -> Result<Option<Constant>, JsValue> {
Ok(self
.0
.additional_registers
.get_constant(register_id.into())
.map_err(to_js)?
.map(Constant::from))
}
pub fn to_json(&self) -> Result<String, JsValue> {
serde_json::to_string_pretty(&self.0.clone())
.map_err(|e| JsValue::from_str(&format!("{}", e)))
}
pub fn to_js_eip12(&self) -> Result<JsValue, JsValue> {
let box_dapp: ErgoBoxJsonEip12 = self.0.clone().into();
<JsValue as JsValueSerdeExt>::from_serde(&box_dapp)
.map_err(|e| JsValue::from_str(&format!("{}", e)))
}
pub fn from_json(json: &str) -> Result<ErgoBox, JsValue> {
serde_json::from_str(json).map(Self).map_err(to_js)
}
pub fn serialized_additional_registers(&self) -> Result<Vec<u8>, JsValue> {
self.0
.additional_registers
.sigma_serialize_bytes()
.map_err(|e| JsValue::from_str(&format!("{}", e)))
}
pub fn sigma_serialize_bytes(&self) -> Result<Vec<u8>, JsValue> {
self.0.sigma_serialize_bytes().map_err(to_js)
}
pub fn sigma_parse_bytes(data: Vec<u8>) -> Result<ErgoBox, JsValue> {
chain::ergo_box::ErgoBox::sigma_parse_bytes(&data)
.map(ErgoBox)
.map_err(to_js)
}
pub fn from_box_candidate(
candidate: &ErgoBoxCandidate,
tx_id: &TxId,
index: u16,
) -> Result<ErgoBox, JsValue> {
let candidate: chain::ergo_box::ErgoBoxCandidate = candidate.0.clone();
chain::ergo_box::ErgoBox::from_box_candidate(&candidate, tx_id.clone().into(), index)
.map_err(to_js)
.map(ErgoBox)
}
}
impl From<ErgoBox> for chain::ergo_box::ErgoBox {
fn from(b: ErgoBox) -> Self {
b.0
}
}
impl From<chain::ergo_box::ErgoBox> for ErgoBox {
fn from(b: chain::ergo_box::ErgoBox) -> Self {
ErgoBox(b)
}
}
#[wasm_bindgen]
#[derive(PartialEq, Eq, Debug, Clone, From, Into)]
pub struct BoxValue(pub(crate) chain::ergo_box::box_value::BoxValue);
#[wasm_bindgen]
impl BoxValue {
#[allow(non_snake_case)]
pub fn SAFE_USER_MIN() -> BoxValue {
BoxValue(chain::ergo_box::box_value::BoxValue::SAFE_USER_MIN)
}
#[allow(non_snake_case)]
pub fn UNITS_PER_ERGO() -> I64 {
(chain::ergo_box::box_value::BoxValue::UNITS_PER_ERGO as i64).into()
}
pub fn from_i64(v: &I64) -> Result<BoxValue, JsValue> {
Ok(BoxValue(
chain::ergo_box::box_value::BoxValue::try_from(i64::from(v.clone()) as u64)
.map_err(to_js)?,
))
}
pub fn as_i64(&self) -> I64 {
self.0.as_i64().into()
}
pub fn to_bytes(&self) -> Vec<u8> {
self.0.as_u64().to_be_bytes().to_vec()
}
}
impl From<&BoxValue> for chain::ergo_box::box_value::BoxValue {
fn from(v: &BoxValue) -> Self {
v.0
}
}
#[wasm_bindgen]
#[derive(PartialEq, Eq, Debug, Clone, From, Into)]
pub struct ErgoBoxAssetsData(ergo_lib::wallet::box_selector::ErgoBoxAssetsData);
#[wasm_bindgen]
impl ErgoBoxAssetsData {
#[wasm_bindgen(constructor)]
pub fn new(value: &BoxValue, tokens: &Tokens) -> Result<ErgoBoxAssetsData, JsValue> {
Ok(ErgoBoxAssetsData(
ergo_lib::wallet::box_selector::ErgoBoxAssetsData {
value: value.clone().into(),
tokens: BoxTokens::opt_empty_vec(
tokens.clone().0.into_iter().map(Into::into).collect(),
)
.map_err(to_js)?,
},
))
}
pub fn value(&self) -> BoxValue {
self.0.value.into()
}
pub fn tokens(&self) -> Tokens {
self.0.tokens.clone().into()
}
}
#[wasm_bindgen]
#[derive(PartialEq, Eq, Debug, Clone)]
pub struct ErgoBoxAssetsDataList(Vec<ErgoBoxAssetsData>);
#[wasm_bindgen]
impl ErgoBoxAssetsDataList {
#[wasm_bindgen(constructor)]
pub fn new() -> Self {
ErgoBoxAssetsDataList(vec![])
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn get(&self, index: usize) -> ErgoBoxAssetsData {
self.0[index].clone()
}
pub fn add(&mut self, elem: &ErgoBoxAssetsData) {
self.0.push(elem.clone());
}
}
impl From<ErgoBoxAssetsDataList> for Vec<ergo_lib::wallet::box_selector::ErgoBoxAssetsData> {
fn from(v: ErgoBoxAssetsDataList) -> Self {
v.0.iter().map(|i| i.0.clone()).collect()
}
}
impl From<Vec<ergo_lib::wallet::box_selector::ErgoBoxAssetsData>> for ErgoBoxAssetsDataList {
fn from(v: Vec<ergo_lib::wallet::box_selector::ErgoBoxAssetsData>) -> Self {
let mut assets = ErgoBoxAssetsDataList::new();
for asset in &v {
assets.add(&ErgoBoxAssetsData(asset.clone()))
}
assets
}
}
#[wasm_bindgen]
#[repr(u8)]
#[derive(PartialEq, Eq, Clone, Debug)]
pub enum NonMandatoryRegisterId {
R4 = 4,
R5 = 5,
R6 = 6,
R7 = 7,
R8 = 8,
R9 = 9,
}
impl NonMandatoryRegisterId {}
impl From<NonMandatoryRegisterId> for chain::ergo_box::NonMandatoryRegisterId {
fn from(v: NonMandatoryRegisterId) -> Self {
use chain::ergo_box::NonMandatoryRegisterId::*;
match v {
NonMandatoryRegisterId::R4 => R4,
NonMandatoryRegisterId::R5 => R5,
NonMandatoryRegisterId::R6 => R6,
NonMandatoryRegisterId::R7 => R7,
NonMandatoryRegisterId::R8 => R8,
NonMandatoryRegisterId::R9 => R9,
}
}
}
impl From<chain::ergo_box::NonMandatoryRegisterId> for NonMandatoryRegisterId {
fn from(v: chain::ergo_box::NonMandatoryRegisterId) -> Self {
use NonMandatoryRegisterId::*;
match v {
chain::ergo_box::NonMandatoryRegisterId::R4 => R4,
chain::ergo_box::NonMandatoryRegisterId::R5 => R5,
chain::ergo_box::NonMandatoryRegisterId::R6 => R6,
chain::ergo_box::NonMandatoryRegisterId::R7 => R7,
chain::ergo_box::NonMandatoryRegisterId::R8 => R8,
chain::ergo_box::NonMandatoryRegisterId::R9 => R9,
}
}
}