use alloc::string::String;
use alloc::vec::Vec;
use core::str::FromStr;
use keetanetwork_account::KeyPairType;
use keetanetwork_block::{BlockHash, BlockTime, IdentifierCreateArguments, MultisigCreateArguments, SetInfo};
use keetanetwork_client::TransactionBuilder;
use num_bigint::BigInt;
use wasm_bindgen::prelude::wasm_bindgen;
use crate::account::Account;
use crate::block::Block;
use crate::certificate::ManageCertificate;
use crate::convert::{
client_error, coded_error, parse_adjust_method, parse_amount, parse_identifier_type, parse_purpose, JsResult,
};
use crate::pending::PendingAccount;
use crate::permissions::{PermissionChange, Permissions};
#[wasm_bindgen]
pub struct Builder {
inner: TransactionBuilder,
}
#[wasm_bindgen]
impl Builder {
#[wasm_bindgen(js_name = forAccount)]
pub fn for_account(&mut self, account: &Account) {
self.inner.for_account(&account.inner());
}
#[wasm_bindgen(js_name = forAccountWithSigner)]
pub fn for_account_with_signer(&mut self, account: &Account, signer: &Account) {
self.inner
.for_account_with_signer(&account.inner(), &signer.inner());
}
pub fn send(&mut self, to: &Account, amount: String, token: &Account, external: Option<String>) -> JsResult<()> {
let amount = parse_amount(&amount)?;
match external {
Some(external) => self
.inner
.send_external(to.inner(), token.inner(), amount, external),
None => self.inner.send(to.inner(), token.inner(), amount),
};
Ok(())
}
pub fn receive(&mut self, from: &Account, amount: String, token: &Account) -> JsResult<()> {
let amount = parse_amount(&amount)?;
self.inner.receive(from.inner(), token.inner(), amount);
Ok(())
}
#[wasm_bindgen(js_name = receiveWith)]
pub fn receive_with(
&mut self,
from: &Account,
amount: String,
token: &Account,
exact: bool,
forward: Option<Account>,
) -> JsResult<()> {
let amount = parse_amount(&amount)?;
let forward = forward.map(|account| account.inner().into());
self.inner
.receive_with(from.inner(), token.inner(), amount, exact, forward);
Ok(())
}
#[wasm_bindgen(js_name = setRep)]
pub fn set_rep(&mut self, to: &Account) {
self.inner.set_rep(&to.inner());
}
#[wasm_bindgen(js_name = setInfo)]
pub fn set_info(
&mut self,
name: String,
description: String,
metadata: String,
default_permission: Option<Permissions>,
) {
let info = SetInfo { name, description, metadata, default_permission: default_permission.map(|p| p.to_core()) };
self.inner.set_info(info);
}
#[wasm_bindgen(js_name = modifyTokenSupply)]
pub fn modify_token_supply(&mut self, amount: String, method: String) -> JsResult<()> {
let amount = parse_amount(&amount)?;
self.inner
.modify_token_supply(amount, parse_adjust_method(&method)?);
Ok(())
}
#[wasm_bindgen(js_name = modifyTokenBalance)]
pub fn modify_token_balance(&mut self, token: &Account, amount: String, method: String) -> JsResult<()> {
let amount = parse_amount(&amount)?;
self.inner
.modify_token_balance(token.inner(), amount, parse_adjust_method(&method)?);
Ok(())
}
#[wasm_bindgen(js_name = generateIdentifier)]
pub fn generate_identifier(&mut self, kind: String) -> JsResult<PendingAccount> {
let handle = self
.inner
.generate_identifier(parse_identifier_type(&kind)?, None);
Ok(PendingAccount::from(handle))
}
#[wasm_bindgen(js_name = generateMultisigIdentifier)]
pub fn generate_multisig_identifier(&mut self, signers: Vec<Account>, quorum: u32) -> PendingAccount {
let signers = signers.iter().map(Account::inner).collect();
let arguments =
IdentifierCreateArguments::Multisig(MultisigCreateArguments { signers, quorum: BigInt::from(quorum) });
let handle = self
.inner
.generate_identifier(KeyPairType::MULTISIG, Some(arguments));
PendingAccount::from(handle)
}
#[wasm_bindgen(js_name = updatePermissions)]
pub fn update_permissions(&mut self, change: &PermissionChange) {
self.inner.modify_permissions(change.to_core());
}
#[wasm_bindgen(js_name = manageCertificate)]
pub fn manage_certificate(&mut self, change: &ManageCertificate) {
self.inner.manage_certificate(change.to_core());
}
#[wasm_bindgen(js_name = withPrevious)]
pub fn with_previous(&mut self, previous: String) -> JsResult<()> {
let previous =
BlockHash::from_str(&previous).map_err(|_| coded_error("INVALID_BLOCK_HASH", "block hash must be hex"))?;
self.inner.with_previous(previous);
Ok(())
}
#[wasm_bindgen(js_name = withPurpose)]
pub fn with_purpose(&mut self, purpose: String) -> JsResult<()> {
self.inner.with_purpose(parse_purpose(&purpose)?);
Ok(())
}
#[wasm_bindgen(js_name = withDate)]
pub fn with_date(&mut self, unix_millis: f64) -> JsResult<()> {
let date = BlockTime::from_unix_millis(unix_millis as i64)
.ok_or_else(|| coded_error("INVALID_DATE", "unix milliseconds out of range"))?;
self.inner.with_date(date);
Ok(())
}
pub async fn build(&mut self) -> JsResult<Vec<Block>> {
let blocks = self.inner.build().await.map_err(client_error)?;
Ok(blocks.into_iter().map(Block::from).collect())
}
}
impl Builder {
pub(crate) fn new(inner: TransactionBuilder) -> Self {
Self { inner }
}
}