use std::convert::TryFrom;
use bounded_vec::OptBoundedVecToVec;
use ergo_lib::ergo_chain_types::Base16DecodedBytes;
use ergo_lib::ergo_chain_types::Digest32;
use ergo_lib::ergotree_ir::chain;
use gloo_utils::format::JsValueSerdeExt;
use js_sys::Uint8Array;
use wasm_bindgen::prelude::*;
use crate::ergo_box::BoxId;
use crate::error_conversion::to_js;
use crate::json::TokenJsonEip12;
use crate::utils::I64;
#[wasm_bindgen]
#[derive(PartialEq, Eq, Debug, Clone)]
pub struct TokenId(chain::token::TokenId);
#[wasm_bindgen]
impl TokenId {
pub fn from_box_id(box_id: &BoxId) -> TokenId {
let box_id: chain::ergo_box::BoxId = box_id.clone().into();
TokenId(chain::token::TokenId::from(box_id))
}
#[allow(clippy::should_implement_trait)]
pub fn from_str(str: &str) -> Result<TokenId, JsValue> {
Base16DecodedBytes::try_from(str.to_string())
.map_err(to_js)
.and_then(|bytes| Digest32::try_from(bytes).map_err(to_js))
.map(|dig| dig.into())
.map(TokenId)
}
pub fn to_str(&self) -> String {
self.0.into()
}
pub fn as_bytes(&self) -> Uint8Array {
Uint8Array::from(self.0.as_ref())
}
}
impl From<TokenId> for chain::token::TokenId {
fn from(t_id: TokenId) -> Self {
t_id.0
}
}
#[wasm_bindgen]
#[derive(PartialEq, Eq, Debug, Clone)]
pub struct TokenAmount(chain::token::TokenAmount);
#[wasm_bindgen]
impl TokenAmount {
pub fn from_i64(v: &I64) -> Result<TokenAmount, JsValue> {
Ok(Self(
chain::token::TokenAmount::try_from(i64::from(v.clone()) as u64).map_err(to_js)?,
))
}
pub fn as_i64(&self) -> I64 {
i64::from(self.0).into()
}
pub fn to_bytes(&self) -> Vec<u8> {
self.0.as_u64().to_be_bytes().to_vec()
}
}
impl From<TokenAmount> for chain::token::TokenAmount {
fn from(ta: TokenAmount) -> Self {
ta.0
}
}
#[wasm_bindgen]
#[derive(PartialEq, Eq, Debug, Clone)]
pub struct Token(chain::token::Token);
#[wasm_bindgen]
impl Token {
#[wasm_bindgen(constructor)]
pub fn new(token_id: &TokenId, amount: &TokenAmount) -> Self {
Token(chain::token::Token {
token_id: token_id.clone().into(),
amount: amount.clone().into(),
})
}
pub fn id(&self) -> TokenId {
TokenId(self.0.token_id)
}
pub fn amount(&self) -> TokenAmount {
TokenAmount(self.0.amount)
}
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 t_dapp: TokenJsonEip12 = self.0.clone().into();
<JsValue as JsValueSerdeExt>::from_serde(&t_dapp)
.map_err(|e| JsValue::from_str(&format!("{}", e)))
}
}
impl From<Token> for chain::token::Token {
fn from(t: Token) -> Self {
t.0
}
}
impl From<chain::token::Token> for Token {
fn from(t: chain::token::Token) -> Self {
Self(t)
}
}
#[wasm_bindgen]
#[derive(PartialEq, Eq, Debug, Clone)]
pub struct Tokens(pub(crate) Vec<Token>);
#[wasm_bindgen]
impl Tokens {
#[wasm_bindgen(constructor)]
pub fn new() -> Self {
Tokens(Vec::new())
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn get(&self, index: usize) -> Result<Token, JsValue> {
self.0
.get(index)
.cloned()
.ok_or_else(|| JsValue::from_str("Index out of bounds"))
}
pub fn add(&mut self, elem: &Token) {
self.0.push(elem.clone());
}
}
impl TryFrom<Tokens> for Option<chain::ergo_box::BoxTokens> {
type Error = JsValue;
fn try_from(tokens: Tokens) -> Result<Self, Self::Error> {
chain::ergo_box::BoxTokens::opt_empty_vec(tokens.0.into_iter().map(Into::into).collect())
.map_err(to_js)
}
}
impl From<Option<chain::ergo_box::BoxTokens>> for Tokens {
fn from(v: Option<chain::ergo_box::BoxTokens>) -> Self {
Tokens(v.to_vec().into_iter().map(|t| t.into()).collect())
}
}