diff --git a/Cargo.lock b/Cargo.lock index 817117917..af3b026df 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9671,10 +9671,13 @@ dependencies = [ name = "tari_scaffolder" version = "0.3.0" dependencies = [ + "anyhow", "clap 3.2.25", "convert_case 0.6.0", "liquid", "liquid-core", + "serde", + "serde_json", "tari_dan_engine", ] diff --git a/applications/tari_scaffolder/Cargo.toml b/applications/tari_scaffolder/Cargo.toml index 80ee12012..0cc8845d3 100644 --- a/applications/tari_scaffolder/Cargo.toml +++ b/applications/tari_scaffolder/Cargo.toml @@ -9,7 +9,10 @@ license.workspace = true [dependencies] tari_dan_engine = { workspace = true } -clap = { workspace = true } +anyhow = { workspace = true } +clap = { workspace = true, features = ["derive"] } liquid = { workspace = true } liquid-core = "0.26.4" convert_case = { workspace = true } +serde_json = "1.0.108" +serde = { version = "1.0.195", features = ["derive"] } diff --git a/applications/tari_scaffolder/README.md b/applications/tari_scaffolder/README.md new file mode 100644 index 000000000..58ddf75bb --- /dev/null +++ b/applications/tari_scaffolder/README.md @@ -0,0 +1,14 @@ +# Tari Scaffolder + +## Basic usage + +```shell +cargo run --release --bin tari_scaffolder -- -c config.json --generator rust-template-cli scaffold /path/to/the/template/source/or/wasm-binary.wasm +``` + +## Generators + +- rust-template-cli - generates a rust cli application for the template +- react-admin-web (TODO) - generates a basic admin web interface for the template using vite.js and React. + + diff --git a/applications/tari_scaffolder/src/template/.gitignore.liquid b/applications/tari_scaffolder/liquid_templates/rust_cli/.gitignore.liquid similarity index 100% rename from applications/tari_scaffolder/src/template/.gitignore.liquid rename to applications/tari_scaffolder/liquid_templates/rust_cli/.gitignore.liquid diff --git a/applications/tari_scaffolder/src/template/Cargo.toml.liquid b/applications/tari_scaffolder/liquid_templates/rust_cli/Cargo.toml.liquid similarity index 96% rename from applications/tari_scaffolder/src/template/Cargo.toml.liquid rename to applications/tari_scaffolder/liquid_templates/rust_cli/Cargo.toml.liquid index d9744c36d..ed8d36068 100644 --- a/applications/tari_scaffolder/src/template/Cargo.toml.liquid +++ b/applications/tari_scaffolder/liquid_templates/rust_cli/Cargo.toml.liquid @@ -5,16 +5,16 @@ edition = "2021" [dependencies] -{% if crates_root == "[crates]" %} -tari_wallet_daemon_client = { git = "https://github.com/tari-project/tari-dan", branch = "development" } -tari_engine_types = { git = "https://github.com/tari-project/tari-dan", branch = "development" } -tari_template_lib = { git = "https://github.com/tari-project/tari-dan", branch = "development" } -tari_transaction = { git = "https://github.com/tari-project/tari-dan", branch = "development" } -{% else %} +{% if crates_root %} tari_wallet_daemon_client={path="{{crates_root}}/clients/wallet_daemon_client"} tari_engine_types={path="{{crates_root}}/dan_layer/engine_types"} tari_template_lib={path="{{crates_root}}/dan_layer/template_lib"} tari_transaction ={path="{{crates_root}}/dan_layer/transaction"} +{% else %} +tari_wallet_daemon_client = { git = "https://github.com/tari-project/tari-dan", branch = "development" } +tari_engine_types = { git = "https://github.com/tari-project/tari-dan", branch = "development" } +tari_template_lib = { git = "https://github.com/tari-project/tari-dan", branch = "development" } +tari_transaction = { git = "https://github.com/tari-project/tari-dan", branch = "development" } {% endif %} tari_utilities ="*" diff --git a/applications/tari_scaffolder/src/template/src/cli.rs.liquid b/applications/tari_scaffolder/liquid_templates/rust_cli/src/cli.rs.liquid similarity index 98% rename from applications/tari_scaffolder/src/template/src/cli.rs.liquid rename to applications/tari_scaffolder/liquid_templates/rust_cli/src/cli.rs.liquid index 3374c739c..cbc93afb2 100644 --- a/applications/tari_scaffolder/src/template/src/cli.rs.liquid +++ b/applications/tari_scaffolder/liquid_templates/rust_cli/src/cli.rs.liquid @@ -102,7 +102,6 @@ use tari_template_lib::args; {% if c.is_method %} pub async fn run(self, mut client: DaemonClient, dump_buckets: bool, is_dry_run: bool, fees: u64) { - let method = "{{c.name}}".to_string(); let mut instructions = vec![]; {% if c.requires_buckets %} @@ -123,7 +122,7 @@ use tari_template_lib::args; instructions.push( Instruction::CallMethod { component_address: ComponentAddress::from_hex(&self.component_address).unwrap(), - method, + method: "{{c.name}}".to_string(), args: args![ {% for arg in c.args %} {% if arg.name != "self" %} @@ -187,7 +186,6 @@ use tari_template_lib::args; {% endif %} let transaction_id = client.submit_instructions(instructions, dump_buckets, false, fees, vec![]).await; - println!("submitted"); let result = client.wait_for_transaction_result(transaction_id).await; println!("result: {:?}", result); diff --git a/applications/tari_scaffolder/src/template/src/daemon_client.rs.liquid b/applications/tari_scaffolder/liquid_templates/rust_cli/src/daemon_client.rs.liquid similarity index 100% rename from applications/tari_scaffolder/src/template/src/daemon_client.rs.liquid rename to applications/tari_scaffolder/liquid_templates/rust_cli/src/daemon_client.rs.liquid diff --git a/applications/tari_scaffolder/src/template/src/main.rs.liquid b/applications/tari_scaffolder/liquid_templates/rust_cli/src/main.rs.liquid similarity index 100% rename from applications/tari_scaffolder/src/template/src/main.rs.liquid rename to applications/tari_scaffolder/liquid_templates/rust_cli/src/main.rs.liquid diff --git a/applications/tari_scaffolder/src/cli.rs b/applications/tari_scaffolder/src/cli.rs index 9f699cadb..44a8a3d83 100644 --- a/applications/tari_scaffolder/src/cli.rs +++ b/applications/tari_scaffolder/src/cli.rs @@ -1,11 +1,11 @@ // Copyright 2022 The Tari Project // SPDX-License-Identifier: BSD-3-Clause -use std::path::PathBuf; +use std::{collections::HashMap, path::PathBuf}; use clap::Parser; -use crate::command::Command; +use crate::{command::Command, generators::GeneratorType}; #[derive(Parser, Debug)] #[clap(author, version, about, long_about = None)] @@ -19,17 +19,20 @@ pub(crate) struct Cli { #[clap(subcommand)] pub command: Command, - #[clap(long)] - pub crates_root: Option, - - #[clap(long, short = 'c', alias = "clean")] + #[clap(long, alias = "clean")] pub clean: bool, - #[clap(long, short = 'o', alias = "output", default_value = "./output")] - pub output_path: PathBuf, + #[clap(long, short = 'o', alias = "output")] + pub output_path: Option, + + #[clap(long, short = 'g', alias = "generator")] + pub generator: GeneratorType, + + #[clap(long, short = 'd', alias = "data", value_parser = parse_hashmap)] + pub data: Option>, - #[clap(long, short = 't', alias = "template")] - pub template_address: Option, + #[clap(long, short = 'c', alias = "config")] + pub generator_config_file: Option, } impl Cli { @@ -37,3 +40,14 @@ impl Cli { Self::parse() } } + +fn parse_hashmap(input: &str) -> anyhow::Result> { + let mut map = HashMap::new(); + for pair in input.split(',') { + let mut parts = pair.splitn(2, ':'); + let key = parts.next().unwrap().to_string(); + let value = parts.next().unwrap_or("").to_string(); + map.insert(key, value); + } + Ok(map) +} diff --git a/applications/tari_scaffolder/src/command/mod.rs b/applications/tari_scaffolder/src/command.rs similarity index 100% rename from applications/tari_scaffolder/src/command/mod.rs rename to applications/tari_scaffolder/src/command.rs diff --git a/applications/tari_scaffolder/src/generators/liquid/mod.rs b/applications/tari_scaffolder/src/generators/liquid/mod.rs new file mode 100644 index 000000000..b79bf5bea --- /dev/null +++ b/applications/tari_scaffolder/src/generators/liquid/mod.rs @@ -0,0 +1,181 @@ +// Copyright 2024 The Tari Project +// SPDX-License-Identifier: BSD-3-Clause + +mod snake_case; + +use std::fs; + +use convert_case::{Case, Casing}; +use tari_dan_engine::abi; + +use crate::generators::{CodeGenerator, GeneratorOpts, TemplateDefinition}; + +pub enum LiquidTemplate { + RustCli, +} + +impl LiquidTemplate { + const fn get_template(&self) -> &'static [(&'static str, &'static str)] { + match self { + LiquidTemplate::RustCli => &[ + ( + "Cargo.toml", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/liquid_templates/rust_cli/Cargo.toml.liquid" + )), + ), + ( + ".gitignore", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/liquid_templates/rust_cli/.gitignore.liquid" + )), + ), + ( + "src/main.rs", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/liquid_templates/rust_cli/src/main.rs.liquid" + )), + ), + ( + "src/cli.rs", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/liquid_templates/rust_cli/src/cli.rs.liquid" + )), + ), + ( + "src/daemon_client.rs", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/liquid_templates/rust_cli/src/daemon_client.rs.liquid" + )), + ), + ], + } + } +} + +pub struct LiquidGenerator { + template: LiquidTemplate, + opts: GeneratorOpts, +} + +impl LiquidGenerator { + pub const fn new(template: LiquidTemplate, opts: GeneratorOpts) -> Self { + Self { template, opts } + } + + fn build_vars(&self, template: &TemplateDefinition) -> liquid_core::Object { + let opts = self.opts.liquid.as_ref().unwrap(); + + let mut globals = liquid::object!({ + "template_name": &template.name, + "commands": [] + }); + globals.extend( + opts.variables + .iter() + .map(|(k, v)| (k.clone().into(), json_value_to_liquid_value(v.clone()))), + ); + + for f in template.template.functions() { + let mut args = vec![]; + let mut is_method = false; + let mut requires_buckets = false; + let mut bucket_output = false; + for a in &f.arguments { + args.push(liquid::object!({ + "name": a.name, + "arg_type": a.arg_type.to_string(), + })); + if a.arg_type.to_string() == "Bucket" { + requires_buckets = true; + } + if a.name == "self" { + is_method = true; + } + } + + if let abi::Type::Other { name } = &f.output { + if name == "Bucket" { + bucket_output = true; + } + } + + let arr = globals.get_mut("commands").unwrap().as_array_mut().unwrap(); + arr.push(liquid_core::Value::Object(liquid::object!({ + "name": f.name, + "title": f.name.to_case(Case::UpperCamel), + "args" : args, + "is_method": is_method, + "is_mut": f.is_mut, + "output": f.output.to_string(), + "requires_buckets": requires_buckets, + "bucket_output": bucket_output, + }))); + } + globals + } +} + +impl CodeGenerator for LiquidGenerator { + fn generate(&self, template: &TemplateDefinition) -> anyhow::Result<()> { + let opts = &self.opts; + fs::create_dir_all(opts.output_path.join("src"))?; + + let templates = self.template.get_template(); + + let vars = self.build_vars(template); + + for (out_file, content) in templates { + fs::write(opts.output_path.join(out_file), replace_tokens(content, &vars)?)?; + } + + if !self.opts.liquid.as_ref().unwrap().skip_format { + std::process::Command::new("cargo") + .args(["fmt"]) + .current_dir(&opts.output_path) + .status()?; + } + + Ok(()) + } +} + +fn replace_tokens(in_file: &str, globals: &liquid_core::Object) -> anyhow::Result { + let template = liquid::ParserBuilder::with_stdlib() + .filter(snake_case::SnakeCase) + .build()? + .parse(in_file)?; + + let built_template = template.render(globals)?; + Ok(built_template) +} + +fn json_value_to_liquid_value(value: serde_json::Value) -> liquid_core::Value { + match value { + serde_json::Value::Null => liquid_core::Value::Nil, + serde_json::Value::Bool(b) => liquid_core::Value::scalar(b), + serde_json::Value::Number(n) => { + if n.is_i64() { + liquid_core::Value::scalar(n.as_i64().unwrap()) + } else { + liquid_core::Value::scalar(n.as_f64().unwrap()) + } + }, + serde_json::Value::String(s) => liquid_core::Value::scalar(s), + serde_json::Value::Array(a) => liquid_core::Value::Array( + a.into_iter() + .map(json_value_to_liquid_value) + .collect::>(), + ), + serde_json::Value::Object(o) => liquid_core::Value::Object( + o.into_iter() + .map(|(k, v)| (k.into(), json_value_to_liquid_value(v))) + .collect::(), + ), + } +} diff --git a/applications/tari_scaffolder/src/snake_case.rs b/applications/tari_scaffolder/src/generators/liquid/snake_case.rs similarity index 100% rename from applications/tari_scaffolder/src/snake_case.rs rename to applications/tari_scaffolder/src/generators/liquid/snake_case.rs diff --git a/applications/tari_scaffolder/src/generators/mod.rs b/applications/tari_scaffolder/src/generators/mod.rs new file mode 100644 index 000000000..8a42c3f11 --- /dev/null +++ b/applications/tari_scaffolder/src/generators/mod.rs @@ -0,0 +1,56 @@ +// Copyright 2024 The Tari Project +// SPDX-License-Identifier: BSD-3-Clause + +use std::{collections::HashMap, path::PathBuf, str::FromStr}; + +use serde::Deserialize; +use tari_dan_engine::{abi::TemplateDef, template::LoadedTemplate}; + +pub mod liquid; + +pub struct TemplateDefinition { + pub name: String, + pub template: TemplateDef, +} + +impl From for TemplateDefinition { + fn from(loaded_template: LoadedTemplate) -> Self { + Self { + name: loaded_template.template_name().to_string(), + template: loaded_template.template_def().clone(), + } + } +} + +pub trait CodeGenerator { + fn generate(&self, template: &TemplateDefinition) -> anyhow::Result<()>; +} + +#[derive(Debug, Clone, Deserialize)] +pub struct GeneratorOpts { + pub output_path: PathBuf, + pub liquid: Option, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct LiquidGeneratorOpts { + #[serde(default)] + pub skip_format: bool, + pub variables: HashMap, +} + +#[derive(Debug, Clone, Copy)] +pub enum GeneratorType { + RustTemplateCli, +} + +impl FromStr for GeneratorType { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result { + match s { + "rust-template-cli" => Ok(GeneratorType::RustTemplateCli), + _ => Err(anyhow::anyhow!("Invalid generator type")), + } + } +} diff --git a/applications/tari_scaffolder/src/main.rs b/applications/tari_scaffolder/src/main.rs index 3274e2f72..50414d41c 100644 --- a/applications/tari_scaffolder/src/main.rs +++ b/applications/tari_scaffolder/src/main.rs @@ -3,28 +3,53 @@ mod cli; mod command; -mod snake_case; +mod generators; -use std::{fs, path::Path}; +use std::fs; -use convert_case::{Case, Casing}; -use liquid::model::Value; use tari_dan_engine::{ - abi, - template::{LoadedTemplate, TemplateModuleLoader}, + template::TemplateModuleLoader, wasm::{compile::compile_template, WasmModule}, }; -use crate::{cli::Cli, LoadedTemplate::Wasm}; +use crate::{ + cli::Cli, + generators::{ + liquid::{LiquidGenerator, LiquidTemplate}, + CodeGenerator, + GeneratorOpts, + TemplateDefinition, + }, +}; -fn main() { +fn main() -> anyhow::Result<()> { let cli = Cli::init(); - if cli.clean && fs::remove_dir_all(&cli.output_path).is_err() { + let mut opts = GeneratorOpts { + output_path: "output/".into(), + liquid: None, + }; + + if let Some(config_file) = &cli.generator_config_file { + let config = fs::read_to_string(config_file)?; + opts = serde_json::from_str(&config)?; + } + + if let Some(output_path) = cli.output_path { + opts.output_path = output_path; + } + + if let Some(ref mut opts) = opts.liquid { + for (k, v) in cli.data.unwrap_or_default() { + opts.variables.insert(k, serde_json::Value::String(v)); + } + } + + if cli.clean && fs::remove_dir_all(&opts.output_path).is_err() { println!("Failed to clean output directory"); } - match &cli.command { + match cli.command { command::Command::Scaffold(scaffold) => { println!("Scaffolding wasm at {:?}", scaffold.wasm_path); let wasm = if scaffold.wasm_path.extension() == Some("wasm".as_ref()) { @@ -34,113 +59,14 @@ fn main() { }; let loaded_template = wasm.load_template().unwrap(); - // dbg!(&loaded_template); - generate(&loaded_template, cli.output_path.as_ref(), &cli) - }, - } - // let config_path = cli.common.config_path(); - // let cfg = load_configuration(config_path, true, &cli)?; - // let config = ApplicationConfig::load_from(&cfg)?; - // println!("Starting validator node on network {}", config.network); - - println!("Hello, world!"); -} - -fn generate(template: &LoadedTemplate, output_path: &Path, cli: &Cli) { - fs::create_dir_all(output_path.join("src")).unwrap(); - fs::write( - output_path.join("Cargo.toml"), - replace_tokens(include_str!("./template/Cargo.toml.liquid"), template, cli), - ) - .unwrap(); - fs::write( - output_path.join(".gitignore"), - replace_tokens(include_str!("./template/.gitignore.liquid"), template, cli), - ) - .unwrap(); - fs::write( - output_path.join("src/main.rs"), - replace_tokens(include_str!("./template/src/main.rs.liquid"), template, cli), - ) - .unwrap(); - fs::write( - output_path.join("src/cli.rs"), - replace_tokens(include_str!("./template/src/cli.rs.liquid"), template, cli), - ) - .unwrap(); - fs::write( - output_path.join("src/daemon_client.rs"), - replace_tokens(include_str!("./template/src/daemon_client.rs.liquid"), template, cli), - ) - .unwrap(); - std::process::Command::new("cargo") - .args(["fmt"]) - .current_dir(output_path) - .status() - .unwrap(); - // todo!() -} - -fn replace_tokens(in_file: &str, loaded_template: &LoadedTemplate, cli: &Cli) -> String { - let template = liquid::ParserBuilder::with_stdlib() - .filter(snake_case::SnakeCase) - .build() - .unwrap() - .parse(in_file) - .unwrap(); - - let mut globals = liquid::object!({ - "template_name": loaded_template.template_name(), - "template_address" : cli.template_address.clone(), - "crates_root": cli.crates_root.as_ref().map(|p| p.display().to_string()).unwrap_or_else(|| "[crates]".to_string()), - "commands": [ - ] - }); - - match loaded_template { - Wasm(loaded_wasm_template) => { - for f in loaded_wasm_template.template_def().functions() { - let arr = globals.get_mut("commands").unwrap().as_array_mut().unwrap(); - let mut args = vec![]; - let mut is_method = false; - let mut requires_buckets = false; - let mut bucket_output = false; - for a in &f.arguments { - dbg!(a); - args.push(liquid::object!({ - "name": a.name, - "arg_type": a.arg_type.to_string(), - })); - if &a.arg_type.to_string() == "Bucket" { - requires_buckets = true; - } - if &a.name == "self" { - is_method = true; - } - } - - if let abi::Type::Other { name } = &f.output { - if name == "Bucket" { - bucket_output = true; - } - } - - arr.push(Value::Object(liquid::object!({ - "name": f.name, - "title": f.name.to_case(Case::UpperCamel), - "args" : args, - "is_method": is_method, - "is_mut": f.is_mut, - "output": f.output.to_string(), - "requires_buckets": requires_buckets, - "bucket_output": bucket_output, - }))); + let template: TemplateDefinition = loaded_template.into(); + match cli.generator { + generators::GeneratorType::RustTemplateCli => { + LiquidGenerator::new(LiquidTemplate::RustCli, opts).generate(&template)? + }, } }, - _ => { - todo!("Not yet supported"); - }, } - dbg!(&globals); - template.render(&globals).unwrap() + + Ok(()) } diff --git a/clients/javascript/wallet_daemon_client/.gitignore b/clients/javascript/wallet_daemon_client/.gitignore new file mode 100644 index 000000000..77738287f --- /dev/null +++ b/clients/javascript/wallet_daemon_client/.gitignore @@ -0,0 +1 @@ +dist/ \ No newline at end of file diff --git a/clients/javascript/wallet_daemon_client/package-lock.json b/clients/javascript/wallet_daemon_client/package-lock.json new file mode 100644 index 000000000..f0d8c53c7 --- /dev/null +++ b/clients/javascript/wallet_daemon_client/package-lock.json @@ -0,0 +1,58 @@ +{ + "name": "@tari/wallet_jrpc_client", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "@tari/wallet_jrpc_client", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "bindings": "file:../../../bindings" + }, + "devDependencies": { + "typescript": "^5.3.3" + } + }, + "../../../bindings": { + "name": "tari-bindings", + "version": "1.0.0", + "license": "ISC", + "devDependencies": { + "shx": "^0.3.4" + } + }, + "node_modules/bindings": { + "resolved": "../../../bindings", + "link": true + }, + "node_modules/typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + } + }, + "dependencies": { + "bindings": { + "version": "file:../../../bindings", + "requires": { + "shx": "^0.3.4" + } + }, + "typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true + } + } +} diff --git a/clients/javascript/wallet_daemon_client/package.json b/clients/javascript/wallet_daemon_client/package.json new file mode 100644 index 000000000..f87081514 --- /dev/null +++ b/clients/javascript/wallet_daemon_client/package.json @@ -0,0 +1,22 @@ +{ + "name": "@tari/wallet_jrpc_client", + "version": "1.0.0", + "description": "Tari wallet JSON-RPC client library", + "scripts": { + "build": "tsc", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "main": "dist/index.js", + "types": "dist/index.d.ts", + "files": [ + "/dist" + ], + "author": "", + "license": "ISC", + "dependencies": { + "bindings": "file:../../../bindings" + }, + "devDependencies": { + "typescript": "^5.3.3" + } +} diff --git a/clients/javascript/wallet_daemon_client/src/index.ts b/clients/javascript/wallet_daemon_client/src/index.ts new file mode 100644 index 000000000..d5012e617 --- /dev/null +++ b/clients/javascript/wallet_daemon_client/src/index.ts @@ -0,0 +1,66 @@ +/* + * // Copyright 2024 The Tari Project + * // SPDX-License-Identifier: BSD-3-Clause + */ + +import { + AccountsGetBalancesRequest, + AccountsGetBalancesResponse, + TransactionSubmitRequest, + TransactionSubmitResponse, + AccountGetRequest, + AccountGetResponse, AccountGetDefaultRequest +} from 'bindings/index'; + +export type { AccountsGetBalancesRequest, AccountsGetBalancesResponse, TransactionSubmitRequest, TransactionSubmitResponse, AccountGetRequest, AccountGetResponse, AccountGetDefaultRequest }; + +export function createClient(url: string): WalletDaemonClient { + return new WalletDaemonClient(url); +} + +export class WalletDaemonClient { + private url: string; + private id: number; + + constructor(url: string) { + this.url = url; + this.id = 0; + } + + accountsGetBalances(params: AccountsGetBalancesRequest): Promise { + return this.__invokeRpc("accounts.get_balances", params); + } + + accountsGet(params: AccountGetRequest): Promise { + return this.__invokeRpc("accounts.get", params); + } + + accountsGetDefault(params: AccountGetDefaultRequest): Promise { + return this.__invokeRpc("accounts.get_default", params); + } + + submitTransaction(params: TransactionSubmitRequest): Promise { + return this.__invokeRpc("transactions.submit", params); + } + + async __invokeRpc(method: string, params: Object = null) { + let id = this.id++; + let response = await fetch(this.url, { + method: "POST", + body: JSON.stringify({ + method: method, + jsonrpc: "2.0", + id: id, + params: params || {}, + }), + headers: { + "Content-Type": "application/json", + }, + }); + let json = await response.json(); + if (json.error) { + throw new Error(`${json.error.code}: ${json.error.message}`); + } + return json.result; + } +} \ No newline at end of file diff --git a/clients/javascript/wallet_daemon_client/tsconfig.json b/clients/javascript/wallet_daemon_client/tsconfig.json new file mode 100644 index 000000000..36ad5eab9 --- /dev/null +++ b/clients/javascript/wallet_daemon_client/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "module": "ES2020", + "target": "ESNext", + "moduleResolution": "Bundler", + "declaration": true, + "outDir": "./dist" + }, + "include": [ + "src/**/*" + ] +}