Repository: ergoplatform/sigma-rust (language: rust)

Issue:
C bindings and Swift wrapper for iOS
The following workflow should be supported:
1. Create a box (with P2PK contract);
2. Create a transaction;
3. Specify transaction inputs;
4. Sign created transaction;
5. Serialize the signed transaction to JSON.


Discussion / hints:

Fix patch:
diff --git a/.editorconfig b/.editorconfig
index be000868e..d80cee0b3 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -10,3 +10,8 @@ trim_trailing_whitespace = true
 [*.{md, markdown, eex}]
 trim_trailing_whitespace = false
 
+[*.swift]
+indent_style = space
+indent_size = 4
+end_of_line = lf
+charset = utf-8
diff --git a/.gitignore b/.gitignore
index b21b12eeb..4dd183aff 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,3 +10,9 @@ wasm-pack.log
 **/dist
 **/docs
 package-lock.json
+
+bindings/ergo-wallet-ios/.build
+bindings/ergo-wallet-ios/build
+bindings/ergo-wallet-ios/Packages
+bindings/ergo-wallet-ios/*.xcodeproj
+bindings/ergo-wallet-ios/xcuserdata/
diff --git a/.travis.yml b/.travis.yml
index fefaf71a5..92edc71b8 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -61,7 +61,7 @@ matrix:
       before_script:
         - curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh -s -- -f
       script:
-        - cd sigma-wasm
+        - cd bindings/ergo-wallet-wasm
         - wasm-pack build
         - wasm-pack test  --firefox --headless
         - wasm-pack test  --firefox --headless --release
@@ -82,20 +82,25 @@ matrix:
       before_script:
         - curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh -s -- -f
       script:
-        - cd sigma-wasm
+        - cd bindings/ergo-wallet-wasm
         - wasm-pack build
         - npm install && npm run test
 
     - name: build for iOS
       os: osx
-      osx_image: xcode11.3
+      osx_image: xcode11.5
       rust: stable
       before_install:
         - rustup target add aarch64-apple-ios x86_64-apple-ios
         - cargo install cargo-lipo
         - cargo install cbindgen
       script:
+        - cd bindings/ergo-wallet-ios
         - cargo lipo --release --targets=aarch64-apple-ios,x86_64-apple-ios
+        - swift package generate-xcodeproj
+        - xcodebuild -project ./ErgoWallet.xcodeproj -xcconfig ./Config/Release.xcconfig -sdk iphoneos
+        - xcodebuild -project ./ErgoWallet.xcodeproj -xcconfig ./Config/Release.xcconfig -sdk iphonesimulator
+
 
 cache: cargo
 # But don't cache the cargo registry
diff --git a/Cargo.toml b/Cargo.toml
index 08e944975..aee1743b8 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -2,7 +2,8 @@
 members = [
     "sigma-ser",
     "sigma-tree",
-    "sigma-wasm",
-    "sigma-tree-c",
+    "ergo-wallet",
+    "bindings/ergo-wallet-wasm",
+    "bindings/ergo-wallet-c",
     "sigma-testutil",
 ]
diff --git a/sigma-tree-c/Cargo.toml b/bindings/ergo-wallet-c/Cargo.toml
similarity index 58%
rename from sigma-tree-c/Cargo.toml
rename to bindings/ergo-wallet-c/Cargo.toml
index c0ca6eb12..8f1f5818f 100644
--- a/sigma-tree-c/Cargo.toml
+++ b/bindings/ergo-wallet-c/Cargo.toml
@@ -1,15 +1,18 @@
 [package]
-name = "sigma-tree-c"
+name = "ergo-wallet-c"
 version = "0.1.0"
 authors = ["Denys Zadorozhnyi <denys@zadorozhnyi.com>"]
 edition = "2018"
-description = "C bindings for sigma-tree"
+description = "Ergo wallet C bindings"
+build = "build.rs"
 
 [lib]
 crate-type = ["staticlib"]
 
 [dependencies]
-sigma-tree = { path = "../sigma-tree", version = "0.1.0" }
+ffi_helpers = "0.2"
+sigma-tree = { path = "../../sigma-tree"}
+ergo-wallet = { path = "../../ergo-wallet"}
 
 [build-dependencies]
 cbindgen = "0.14"
@@ -17,3 +20,4 @@ cbindgen = "0.14"
 [profile.release]
 # Tell `rustc` to optimize for small code size.
 opt-level = "s"
+lto = true
diff --git a/bindings/ergo-wallet-c/build.rs b/bindings/ergo-wallet-c/build.rs
new file mode 100644
index 000000000..56e9b6bf8
--- /dev/null
+++ b/bindings/ergo-wallet-c/build.rs
@@ -0,0 +1,15 @@
+extern crate cbindgen;
+
+use std::env;
+
+fn main() {
+    let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
+    let config = cbindgen::Config::from_file("cbindgen.toml").expect("No cbindgen.toml found");
+
+    cbindgen::Builder::new()
+        .with_crate(crate_dir)
+        .with_config(config)
+        .generate()
+        .expect("Unable to generate bindings")
+        .write_to_file("h/ergo_wallet.h");
+}
diff --git a/bindings/ergo-wallet-c/cbindgen.toml b/bindings/ergo-wallet-c/cbindgen.toml
new file mode 100644
index 000000000..2aff65bea
--- /dev/null
+++ b/bindings/ergo-wallet-c/cbindgen.toml
@@ -0,0 +1,144 @@
+# This is a template cbindgen.toml file with all of the default values.
+# Some values are commented out because their absence is the real default.
+#
+# See https://github.com/eqrion/cbindgen/blob/master/docs.md#cbindgentoml
+# for detailed documentation of every option here.
+
+
+language = "C"
+
+
+
+############## Options for Wrapping the Contents of the Header #################
+
+# header = "/* Text to put at the beginning of the generated file. Probably a license. */"
+# trailer = "/* Text to put at the end of the generated file */"
+# include_guard = "my_bindings_h"
+# pragma_once = true
+autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */"
+include_version = false
+# namespace = "my_namespace"
+namespaces = []
+using_namespaces = []
+sys_includes = []
+includes = []
+no_includes = false
+after_includes = ""
+
+
+
+
+############################ Code Style Options ################################
+
+braces = "SameLine"
+line_length = 100
+tab_width = 2
+documentation_style = "auto"
+
+
+
+
+
+############################# Codegen Options ##################################
+
+style = "both"
+
+
+
+[defines]
+# "target_os = freebsd" = "DEFINE_FREEBSD"
+# "feature = serde" = "DEFINE_SERDE"
+
+
+
+[export]
+include = []
+exclude = []
+# prefix = "CAPI_"
+item_types = []
+renaming_overrides_prefixing = false
+
+
+
+[export.rename]
+
+
+
+[export.body]
+
+
+
+
+[fn]
+rename_args = "None"
+# must_use = "MUST_USE_FUNC"
+# prefix = "START_FUNC"
+# postfix = "END_FUNC"
+args = "auto"
+sort_by = "Name"
+
+
+
+
+[struct]
+rename_fields = "None"
+# must_use = "MUST_USE_STRUCT"
+derive_constructor = false
+derive_eq = false
+derive_neq = false
+derive_lt = false
+derive_lte = false
+derive_gt = false
+derive_gte = false
+
+
+
+
+[enum]
+rename_variants = "None"
+# must_use = "MUST_USE_ENUM"
+add_sentinel = false
+prefix_with_name = false
+derive_helper_methods = false
+derive_const_casts = false
+derive_mut_casts = false
+# cast_assert_name = "ASSERT"
+derive_tagged_enum_destructor = false
+derive_tagged_enum_copy_constructor = false
+enum_class = true
+private_default_tagged_enum_constructor = false
+
+
+
+
+[const]
+allow_static_const = true
+allow_constexpr = false
+
+
+
+
+[macro_expansion]
+bitflags = false
+
+
+
+
+
+
+############## Options for How Your Rust library Should Be Parsed ##############
+
+[parse]
+parse_deps = false
+# include = []
+exclude = []
+clean = false
+extra_bindings = []
+
+
+
+[parse.expand]
+crates = []
+all_features = false
+default_features = true
+features = []
diff --git a/bindings/ergo-wallet-c/h/ergo_wallet.h b/bindings/ergo-wallet-c/h/ergo_wallet.h
new file mode 100644
index 000000000..b33873eff
--- /dev/null
+++ b/bindings/ergo-wallet-c/h/ergo_wallet.h
@@ -0,0 +1,96 @@
+/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */
+
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+
+typedef struct Address Address;
+
+typedef struct DataInputBoxes DataInputBoxes;
+
+typedef struct ErgoBoxCandidate ErgoBoxCandidate;
+
+typedef struct ErgoStateContext ErgoStateContext;
+
+typedef struct Error Error;
+
+typedef struct OutputBoxes OutputBoxes;
+
+typedef struct Transaction Transaction;
+
+typedef struct UnspentBoxes UnspentBoxes;
+
+typedef struct Wallet Wallet;
+
+typedef Error *ErrorPtr;
+
+typedef Address *AddressPtr;
+
+typedef Transaction *TransactionPtr;
+
+typedef ErgoBoxCandidate *ErgoBoxCandidatePtr;
+
+typedef ErgoStateContext *ErgoStateContextPtr;
+
+typedef OutputBoxes *OutputBoxesPtr;
+
+typedef UnspentBoxes *UnspentBoxesPtr;
+
+typedef Wallet *WalletPtr;
+
+typedef DataInputBoxes *DataInputBoxesPtr;
+
+ErrorPtr ergo_wallet_address_delete(AddressPtr _address);
+
+ErrorPtr ergo_wallet_address_from_testnet(const char *_address_str, AddressPtr *_address_out);
+
+void ergo_wallet_delete_error(ErrorPtr error);
+
+ErrorPtr ergo_wallet_delete_signed_tx(TransactionPtr _transaction);
+
+void ergo_wallet_delete_string(char *ptr);
+
+ErrorPtr ergo_wallet_ergo_box_candidate_delete(ErgoBoxCandidatePtr _ergo_box_candidate);
+
+ErrorPtr ergo_wallet_ergo_box_candidate_new_pay_to_address(AddressPtr _recipient,
+                                                           uint64_t _value,
+                                                           uint32_t _creation_height,
+                                                           ErgoBoxCandidatePtr *_ergo_box_candidate_out);
+
+ErrorPtr ergo_wallet_ergo_state_context_delete(ErgoStateContextPtr _ergo_state_context);
+
+ErrorPtr ergo_wallet_ergo_state_context_from_json(const char *_json_str,
+                                                  ErgoStateContextPtr *_ergo_state_context_out);
+
+char *ergo_wallet_error_to_string(ErrorPtr error);
+
+ErrorPtr ergo_wallet_output_boxes_delete(OutputBoxesPtr _output_boxes);
+
+ErrorPtr ergo_wallet_output_boxes_new(ErgoBoxCandidatePtr _ergo_box_candidate,
+                                      OutputBoxesPtr *_output_boxes_out);
+
+ErrorPtr ergo_wallet_signed_tx_to_json(TransactionPtr _transaction, const char **_json_str_out);
+
+ErrorPtr ergo_wallet_unspent_boxes_delete(UnspentBoxesPtr _unspent_boxes);
+
+ErrorPtr ergo_wallet_unspent_boxes_from_json(const char *_json_str,
+                                             UnspentBoxesPtr *_unspent_boxes_out);
+
+ErrorPtr ergo_wallet_wallet_delete(WalletPtr _wallet);
+
+ErrorPtr ergo_wallet_wallet_from_mnemonic(const char *_mnemonic_phrase,
+                                          const uint8_t *_mnemonic_password,
+                                          uintptr_t _mnemonic_password_length,
+                                          WalletPtr *_wallet_out);
+
+ErrorPtr ergo_wallet_wallet_new_signed_tx(WalletPtr _wallet,
+                                          ErgoStateContextPtr _state_context,
+                                          UnspentBoxesPtr _unspent_boxes,
+                                          DataInputBoxesPtr _data_input_boxes,
+                                          OutputBoxesPtr _output_boxes,
+                                          AddressPtr _send_change_to,
+                                          uint64_t _min_change_value,
+                                          uint64_t _tx_fee_amount,
+                                          TransactionPtr *_transaction_out);
diff --git a/bindings/ergo-wallet-c/src/error.rs b/bindings/ergo-wallet-c/src/error.rs
new file mode 100644
index 000000000..54fb9fe45
--- /dev/null
+++ b/bindings/ergo-wallet-c/src/error.rs
@@ -0,0 +1,16 @@
+use std::{error, fmt, result};
+
+pub type Result<T> = result::Result<T, Box<dyn error::Error + 'static>>;
+
+#[derive(Debug)]
+pub struct Error {
+    details: Box<dyn error::Error + 'static>,
+}
+
+pub type ErrorPtr = *mut Error;
+
+impl fmt::Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(self.details.as_ref(), f)
+    }
+}
diff --git a/bindings/ergo-wallet-c/src/lib.rs b/bindings/ergo-wallet-c/src/lib.rs
new file mode 100644
index 000000000..c7bc7ea57
--- /dev/null
+++ b/bindings/ergo-wallet-c/src/lib.rs
@@ -0,0 +1,185 @@
+//! WASM bindings for sigma-tree
+
+// Coding conventions
+#![deny(non_upper_case_globals)]
+#![deny(non_camel_case_types)]
+#![deny(non_snake_case)]
+#![deny(unused_mut)]
+#![deny(dead_code)]
+#![deny(unused_imports)]
+// #![deny(missing_docs)]
+#![allow(clippy::missing_safety_doc)]
+
+use sigma_tree::chain;
+
+use std::{ffi::CString, os::raw::c_char};
+
+// TODO: share code with JNI bindings
+// TODO: add docs
+// TODO: extract into files/modules?
+
+mod error;
+pub use error::*;
+
+pub struct ErgoStateContext(ergo_wallet::ErgoStateContext);
+pub type ErgoStateContextPtr = *mut ErgoStateContext;
+
+#[no_mangle]
+pub unsafe extern "C" fn ergo_wallet_ergo_state_context_from_json(
+    _json_str: *const c_char,
+    _ergo_state_context_out: *mut ErgoStateContextPtr,
+) -> ErrorPtr {
+    todo!()
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn ergo_wallet_ergo_state_context_delete(
+    _ergo_state_context: ErgoStateContextPtr,
+) -> ErrorPtr {
+    todo!()
+}
+
+pub struct ErgoBoxCandidate(chain::ErgoBoxCandidate);
+pub type ErgoBoxCandidatePtr = *mut ErgoBoxCandidate;
+
+#[no_mangle]
+pub extern "C" fn ergo_wallet_ergo_box_candidate_new_pay_to_address(
+    _recipient: AddressPtr,
+    _value: u64,
+    _creation_height: u32,
+    _ergo_box_candidate_out: *mut ErgoBoxCandidatePtr,
+) -> ErrorPtr {
+    todo!()
+}
+
+#[no_mangle]
+pub extern "C" fn ergo_wallet_ergo_box_candidate_delete(
+    _ergo_box_candidate: ErgoBoxCandidatePtr,
+) -> ErrorPtr {
+    todo!()
+}
+
+pub struct Address(Box<dyn chain::Address>);
+pub type AddressPtr = *mut Address;
+
+#[no_mangle]
+pub extern "C" fn ergo_wallet_address_from_testnet(
+    _address_str: *const c_char,
+    _address_out: *mut AddressPtr,
+) -> ErrorPtr {
+    todo!()
+}
+
+#[no_mangle]
+pub extern "C" fn ergo_wallet_address_delete(_address: AddressPtr) -> ErrorPtr {
+    todo!()
+}
+
+pub struct UnspentBoxes(Vec<chain::ErgoBoxCandidate>);
+pub type UnspentBoxesPtr = *mut UnspentBoxes;
+
+#[no_mangle]
+pub extern "C" fn ergo_wallet_unspent_boxes_from_json(
+    _json_str: *const c_char,
+    _unspent_boxes_out: *mut UnspentBoxesPtr,
+) -> ErrorPtr {
+    todo!()
+}
+
+#[no_mangle]
+pub extern "C" fn ergo_wallet_unspent_boxes_delete(_unspent_boxes: UnspentBoxesPtr) -> ErrorPtr {
+    todo!()
+}
+
+pub struct DataInputBoxes(Vec<chain::ErgoBoxCandidate>);
+pub type DataInputBoxesPtr = *mut DataInputBoxes;
+
+pub struct OutputBoxes(Vec<chain::ErgoBoxCandidate>);
+pub type OutputBoxesPtr = *mut OutputBoxes;
+
+#[no_mangle]
+pub extern "C" fn ergo_wallet_output_boxes_new(
+    _ergo_box_candidate: ErgoBoxCandidatePtr,
+    _output_boxes_out: *mut OutputBoxesPtr,
+) -> ErrorPtr {
+    todo!()
+}
+
+#[no_mangle]
+pub extern "C" fn ergo_wallet_output_boxes_delete(_output_boxes: OutputBoxesPtr) -> ErrorPtr {
+    todo!()
+}
+
+pub struct Wallet();
+pub type WalletPtr = *mut Wallet;
+
+#[no_mangle]
+pub extern "C" fn ergo_wallet_wallet_from_mnemonic(
+    _mnemonic_phrase: *const c_char,
+    _mnemonic_password: *const u8,
+    _mnemonic_password_length: usize,
+    _wallet_out: *mut WalletPtr,
+) -> ErrorPtr {
+    todo!()
+}
+
+#[no_mangle]
+pub extern "C" fn ergo_wallet_wallet_delete(_wallet: WalletPtr) -> ErrorPtr {
+    todo!()
+}
+
+#[no_mangle]
+pub extern "C" fn ergo_wallet_wallet_new_signed_tx(
+    _wallet: WalletPtr,
+    _state_context: ErgoStateContextPtr,
+    _unspent_boxes: UnspentBoxesPtr,
+    _data_input_boxes: DataInputBoxesPtr, // can be null
+    _output_boxes: OutputBoxesPtr,
+    _send_change_to: AddressPtr,
+    _min_change_value: u64,
+    _tx_fee_amount: u64,
+    _transaction_out: *mut TransactionPtr,
+) -> ErrorPtr {
+    todo!()
+}
+
+pub struct Transaction(chain::Transaction);
+pub type TransactionPtr = *mut Transaction;
+
+#[no_mangle]
+pub extern "C" fn ergo_wallet_delete_signed_tx(_transaction: TransactionPtr) -> ErrorPtr {
+    todo!()
+}
+
+#[no_mangle]
+pub extern "C" fn ergo_wallet_signed_tx_to_json(
+    _transaction: TransactionPtr,
+    _json_str_out: *mut *const c_char,
+) -> ErrorPtr {
+    todo!()
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn ergo_wallet_delete_string(ptr: *mut c_char) {
+    if !ptr.is_null() {
+        let cstring = CString::from_raw(ptr);
+        std::mem::drop(cstring)
+    }
+}
+
+#[no_mangle]
+pub extern "C" fn ergo_wallet_delete_error(error: ErrorPtr) {
+    if !error.is_null() {
+        let boxed = unsafe { Box::from_raw(error) };
+        std::mem::drop(boxed);
+    }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn ergo_wallet_error_to_string(error: ErrorPtr) -> *mut c_char {
+    if let Some(error) = error.as_ref() {
+        CString::new(error.to_string()).unwrap().into_raw()
+    } else {
+        CString::new(b"success".to_vec()).unwrap().into_raw()
+    }
+}
diff --git a/bindings/ergo-wallet-ios/Config/Release.xcconfig b/bindings/ergo-wallet-ios/Config/Release.xcconfig
new file mode 100644
index 000000000..fc3b2594d
--- /dev/null
+++ b/bindings/ergo-wallet-ios/Config/Release.xcconfig
@@ -0,0 +1,11 @@
+CONFIGURATION = Release
+TARGET_NAME = ErgoWallet
+SUPPORTED_PLATFORMS = iphonesimulator iphoneos
+VALID_ARCHS = arm64 x86_64
+ENABLE_BITCODE = NO
+BUILD_LIBRARY_FOR_DISTRIBUTION = YES
+HEADER_SEARCH_PATHS = $(inherited) $(SRCROOT)/../ergo-wallet-c/h
+OTHER_LDFLAGS = $(inherited) -L"$(SRCROOT)/../../target/universal/release" -lergo_wallet_c
+PRODUCT_BUNDLE_IDENTIFIER = org.ergoplatform.wallet
+FRAMEWORK_VERSION = 0.1.0-pre1
+
diff --git a/bindings/ergo-wallet-ios/Package.swift b/bindings/ergo-wallet-ios/Package.swift
new file mode 100644
index 000000000..2d3bead78
--- /dev/null
+++ b/bindings/ergo-wallet-ios/Package.swift
@@ -0,0 +1,20 @@
+// swift-tools-version:5.2
+
+import PackageDescription
+
+let package = Package(
+    name: "ErgoWallet",
+    products: [
+        .library(
+            name: "ErgoWallet",
+            targets: ["ErgoWallet"]
+        )
+    ],
+    targets: [
+        .systemLibrary(name: "ErgoWalletC"),
+        .target(
+            name: "ErgoWallet",
+            dependencies: ["ErgoWalletC"]
+        ),
+    ]
+)
diff --git a/bindings/ergo-wallet-ios/Sources/ErgoWallet/ErgoWallet.swift b/bindings/ergo-wallet-ios/Sources/ErgoWallet/ErgoWallet.swift
new file mode 100644
index 000000000..a69602b42
--- /dev/null
+++ b/bindings/ergo-wallet-ios/Sources/ErgoWallet/ErgoWallet.swift
@@ -0,0 +1,175 @@
+import Foundation
+import ErgoWalletC
+
+// TODO: extract into files
+
+enum WalletError: Error {
+    case walletCError(reason: String)
+}
+
+class UnspentBoxes {
+    internal var pointer: UnspentBoxesPtr
+
+    init(withJson json: String) throws {
+        self.pointer = try UnspentBoxes.from_json(json: json)
+    }
+
+    private static func from_json(json: String) throws -> UnspentBoxesPtr {
+        var unspentBoxesPtr: UnspentBoxesPtr?
+        let error = json.withCString { cs in
+            ergo_wallet_unspent_boxes_from_json(cs, &unspentBoxesPtr)
+        }
+        try checkError(error)
+        return unspentBoxesPtr!
+    }
+
+    deinit {
+        ergo_wallet_unspent_boxes_delete(self.pointer)
+    }
+}
+
+private func checkError(_ error: ErrorPtr?) throws {
+    if error == nil {
+        return
+    }
+
+    let cStringReason = ergo_wallet_error_to_string(error)
+    let reason = String(cString: cStringReason!)
+    ergo_wallet_delete_string(cStringReason)
+    ergo_wallet_delete_error(error)
+    throw WalletError.walletCError(reason: reason)
+}
+
+class Transaction {
+    private var pointer: TransactionPtr
+
+    internal init(withRawPointer pointer: TransactionPtr) {
+        self.pointer = pointer
+    }
+
+    func toJson() throws -> String {
+        var cStr: UnsafePointer<CChar>?
+        let error = ergo_wallet_signed_tx_to_json(self.pointer, &cStr)
+        try checkError(error)
+        let str = String(cString: cStr!)
+        ergo_wallet_delete_string(UnsafeMutablePointer(mutating: cStr))
+        return str
+    }
+
+    deinit {
+        ergo_wallet_delete_signed_tx(self.pointer)
+    }
+}
+
+class ErgoStateContext {
+    internal var pointer: ErgoStateContextPtr
+
+    init(withJson json: String) throws {
+        self.pointer = try ErgoStateContext.fromJson(json: json)
+    }
+
+    private static func fromJson(json: String) throws -> ErgoStateContextPtr {
+        var ergoStateContextPtr: ErgoStateContextPtr?
+        let error = json.withCString { cs in
+            ergo_wallet_ergo_state_context_from_json(cs, &ergoStateContextPtr)
+        }
+        try checkError(error)
+        return ergoStateContextPtr!
+    }
+
+    deinit {
+        ergo_wallet_ergo_state_context_delete(self.pointer)
+    }
+}
+
+class Address {
+    internal var pointer: AddressPtr
+
+    init(withTestnetAddress addressStr: String) throws {
+        self.pointer = try Address.fromTestnetAddress(addressStr: addressStr)
+    }
+
+    private static func fromTestnetAddress(addressStr: String) throws -> AddressPtr {
+        var ptr: AddressPtr?
+        let error = addressStr.withCString { cs in
+            ergo_wallet_address_from_testnet(cs, &ptr)
+        }
+        try checkError(error)
+        return ptr!
+    }
+    
+    deinit {
+        ergo_wallet_address_delete(self.pointer)
+    }
+}
+
+class ErgoBoxCandidate {
+    internal var pointer: ErgoBoxCandidatePtr
+
+    internal init(withRawPointer pointer: ErgoBoxCandidatePtr) {
+        self.pointer = pointer
+    }
+
+    static func payToAddress(recipient: Address,
+                             value: UInt64, creationHeight: UInt32) throws -> ErgoBoxCandidate {
+        var ergoBoxCandidatePtr: ErgoBoxCandidatePtr?
+        let error = ergo_wallet_ergo_box_candidate_new_pay_to_address(recipient.pointer, 
+                                                                     value,
+                                                                     creationHeight,
+                                                                     &ergoBoxCandidatePtr)
+        try checkError(error)
+        return ErgoBoxCandidate(withRawPointer: ergoBoxCandidatePtr!)
+    }
+
+    deinit {
+        ergo_wallet_ergo_box_candidate_delete(self.pointer)
+    }
+}
+
+class OutputBoxes {
+    internal var pointer: OutputBoxesPtr
+
+    init(box: ErgoBoxCandidate) throws {
+        var ptr: OutputBoxesPtr?
+        let error = ergo_wallet_output_boxes_new(box.pointer, &ptr)
+        try checkError(error)
+        self.pointer = ptr!
+    }
+
+    deinit {
+        ergo_wallet_output_boxes_delete(self.pointer)
+    }
+}
+
+class Wallet {
+    internal var pointer: WalletPtr
+
+    init(withMnemonic mnemonicPhrase: String) throws {
+        var ptr: WalletPtr?
+        let error = mnemonicPhrase.withCString { mnemonicPhraseC in
+            ergo_wallet_wallet_from_mnemonic(mnemonicPhraseC, nil, 0, &ptr)
+        }
+        try checkError(error)
+        self.pointer = ptr!
+    }
+
+    func new_signed_tx(ergoStateContext: ErgoStateContext, 
+                              unspentBoxes: UnspentBoxes, 
+                              outputBoxes: OutputBoxes,
+                              sendChangeTo: Address, 
+                              minChangeValue: UInt64,
+                              txFeeAmount: UInt64) throws -> Transaction {
+        var transactionPtr: TransactionPtr?
+        let error = ergo_wallet_wallet_new_signed_tx(self.pointer, 
+                                              ergoStateContext.pointer,
+                                              unspentBoxes.pointer, 
+                                              nil, // data input boxes
+                                              outputBoxes.pointer,
+                                              sendChangeTo.pointer,
+                                              minChangeValue, 
+                                              txFeeAmount, 
+                                              &transactionPtr)
+        try checkError(error)
+        return Transaction(withRawPointer: transactionPtr!)
+    }
+}
diff --git a/bindings/ergo-wallet-ios/Sources/ErgoWalletC/module.modulemap b/bindings/ergo-wallet-ios/Sources/ErgoWalletC/module.modulemap
new file mode 100644
index 000000000..53c45c5a8
--- /dev/null
+++ b/bindings/ergo-wallet-ios/Sources/ErgoWalletC/module.modulemap
@@ -0,0 +1,4 @@
+module ErgoWalletC {
+    umbrella header "shim.h"
+    export *
+}
diff --git a/bindings/ergo-wallet-ios/Sources/ErgoWalletC/shim.h b/bindings/ergo-wallet-ios/Sources/ErgoWalletC/shim.h
new file mode 100644
index 000000000..207f86805
--- /dev/null
+++ b/bindings/ergo-wallet-ios/Sources/ErgoWalletC/shim.h
@@ -0,0 +1,6 @@
+#ifndef ERGO_WALLET_SHIM_H_
+#define ERGO_WALLET_SHIM_H_
+
+#include "ergo_wallet.h"
+
+#endif /* ERGO_WALLET_SHIM_H_ */
diff --git a/sigma-wasm/.babelrc b/bindings/ergo-wallet-wasm/.babelrc
similarity index 100%
rename from sigma-wasm/.babelrc
rename to bindings/ergo-wallet-wasm/.babelrc
diff --git a/sigma-wasm/Cargo.toml b/bindings/ergo-wallet-wasm/Cargo.toml
similarity index 82%
rename from sigma-wasm/Cargo.toml
rename to bindings/ergo-wallet-wasm/Cargo.toml
index 811d8eb13..9a919732a 100644
--- a/sigma-wasm/Cargo.toml
+++ b/bindings/ergo-wallet-wasm/Cargo.toml
@@ -1,9 +1,9 @@
 [package]
-name = "sigma-tree-wasm"
+name = "ergo-wallet-wasm"
 version = "0.1.0"
 authors = ["Denys Zadorozhnyi <denys@zadorozhnyi.com>"]
 edition = "2018"
-description = "WASM bindings for sigma-tree"
+description = "Ergo wallet WASM bindings"
 
 [lib]
 crate-type = ["cdylib", "rlib"]
@@ -13,7 +13,8 @@ default = ["console_error_panic_hook"]
 
 [dependencies]
 serde = { version = "1.0", features = ["derive"]}
-sigma-tree = { path = "../sigma-tree", features = ["with-serde"] }
+ergo-wallet = { path = "../../ergo-wallet", features = ["with-serde"] }
+sigma-tree = { path = "../../sigma-tree", features = ["with-serde"] }
 # used in elliptic-curve(in sigma-tree), compiled here with WASM support
 getrandom = {version = "0.1", features = ["wasm-bindgen"]}
 # The `console_error_panic_hook` crate provides better debugging of panics by
@@ -29,7 +30,7 @@ features = ["serde-serialize"]
 [dev-dependencies]
 wasm-bindgen-test = "0.3.10"
 proptest-derive = "0.2"
-sigma-testutil = { path = "../sigma-testutil" }
+sigma-testutil = { path = "../../sigma-testutil" }
 
 [dev-dependencies.proptest]
 # wasm support, via https://altsysrq.github.io/proptest-book/proptest/wasm.html
diff --git a/sigma-wasm/README.md b/bindings/ergo-wallet-wasm/README.md
similarity index 100%
rename from sigma-wasm/README.md
rename to bindings/ergo-wallet-wasm/README.md
diff --git a/sigma-wasm/jsdoc.json b/bindings/ergo-wallet-wasm/jsdoc.json
similarity index 100%
rename from sigma-wasm/jsdoc.json
rename to bindings/ergo-wallet-wasm/jsdoc.json
diff --git a/sigma-wasm/package.json b/bindings/ergo-wallet-wasm/package.json
similarity index 91%
rename from sigma-wasm/package.json
rename to bindings/ergo-wallet-wasm/package.json
index 5f13c1b9d..0a17e5175 100644
--- a/sigma-wasm/package.json
+++ b/bindings/ergo-wallet-wasm/package.json
@@ -3,7 +3,7 @@
         "build": "webpack",
         "serve": "wasm-pack build --target browser && webpack-dev-server",
         "test": "wasm-pack build --target nodejs && mocha --require @babel/register --require @babel/polyfill 'tests/test*.js'",
-        "doc": "jsdoc -c jsdoc.json pkg/sigma_tree_wasm.js README.md -d docs"
+        "doc": "jsdoc -c jsdoc.json pkg/ergo_wallet_wasm.js README.md -d docs"
     },
     "devDependencies": {
         "@babel/core": "^7.6.4",
diff --git a/sigma-wasm/src/lib.rs b/bindings/ergo-wallet-wasm/src/lib.rs
similarity index 76%
rename from sigma-wasm/src/lib.rs
rename to bindings/ergo-wallet-wasm/src/lib.rs
index 70130511b..771f2ee31 100644
--- a/sigma-wasm/src/lib.rs
+++ b/bindings/ergo-wallet-wasm/src/lib.rs
@@ -73,32 +73,35 @@ impl Address {
     }
 }
 
-/// Secret key for prover
+/// Transaction inputs, array of ErgoBoxCandidate
 #[wasm_bindgen]
-pub struct SecretKey(chain::SecretKey);
+pub struct UnspentBoxes(Vec<chain::ErgoBoxCandidate>);
 
 #[wasm_bindgen]
-impl SecretKey {
-    /// Decode from string
-    pub fn parse(_: &str) -> Result<SecretKey, JsValue> {
-        // not implemented, see https://github.com/ergoplatform/sigma-rust/issues/33
-        Ok(SecretKey(chain::SecretKey::random_dlog()))
+impl UnspentBoxes {
+    /// parse ErgoBoxCandidate array from json
+    #[allow(clippy::boxed_local)]
+    pub fn from_boxes(_boxes: Box<[JsValue]>) -> UnspentBoxes {
+        // box in boxes.into_iter() {
+        //     let _box: chain::ErgoBoxCandidate = jbox.into_serde().unwrap();
+        // }
+        UnspentBoxes(vec![])
     }
 }
-
-/// Transaction inputs, array of ErgoBoxCandidate
+///
+/// Transaction data inputs, array of ErgoBoxCandidate
 #[wasm_bindgen]
-pub struct TxInputs(Vec<chain::ErgoBoxCandidate>);
+pub struct TxDataInputs(Vec<chain::ErgoBoxCandidate>);
 
 #[wasm_bindgen]
-impl TxInputs {
+impl TxDataInputs {
     /// parse ErgoBoxCandidate array from json
     #[allow(clippy::boxed_local)]
-    pub fn from_boxes(_boxes: Box<[JsValue]>) -> TxInputs {
+    pub fn from_boxes(_boxes: Box<[JsValue]>) -> TxDataInputs {
         // box in boxes.into_iter() {
         //     let _box: chain::ErgoBoxCandidate = jbox.into_serde().unwrap();
         // }
-        TxInputs(vec![])
+        TxDataInputs(vec![])
     }
 }
 
@@ -193,19 +196,49 @@ impl Transaction {
     }
 }
 
-/// Create a signed transaction from:
-/// `inputs` - boxes [`ErgoBoxCandidate`] that will be spent
-/// `outputs` - boxes that will be created in this transaction
-/// `send_change_to` - address for the change (total value of input - total value of outputs)
-/// that will be put in a new box that will be added to `outputs`
-/// `sk` - secret key to sign the transaction (make proofs for inputs)
-#[wasm_bindgen]
-pub fn new_signed_transaction(
-    _inputs: TxInputs,
-    _outputs: TxOutputs,
-    _send_change_to: Address,
-    _sk: SecretKey,
-) -> Result<Transaction, JsValue> {
-    // not implemented, see https://github.com/ergoplatform/sigma-rust/issues/34
-    Err(JsValue::from_str("Error!"))
+/// TBD
+#[wasm_bindgen]
+pub struct ErgoStateContext(ergo_wallet::ErgoStateContext);
+
+#[wasm_bindgen]
+impl ErgoStateContext {
+    /// empty (dummy) context (for signing P2PK tx only)
+    pub fn dummy() -> ErgoStateContext {
+        ErgoStateContext(ergo_wallet::ErgoStateContext::dummy())
+    }
+}
+
+/// TBD
+#[wasm_bindgen]
+pub struct Wallet();
+
+#[wasm_bindgen]
+impl Wallet {
+    /// Create wallet instance loading secret key from mnemonic
+    pub fn from_mnemonic(_mnemonic_phrase: &str, _mnemonic_pass: &str) -> Wallet {
+        Wallet()
+    }
+
+    /// Create a signed transaction from:
+    /// `unspent_boxes` - unspent boxes [`ErgoBoxCandidate`] from which transaction
+    /// inputs (boxes to spend) will be selected
+    /// `outputs` - boxes that will be created in this transaction
+    /// `send_change_to` - address for the change (total value of input - total value of outputs)
+    /// that will be put in a new box that will be added to `outputs`
+    /// `sk` - secret key to sign the transaction (make proofs for inputs)
+    #[allow(clippy::too_many_arguments)]
+    #[wasm_bindgen]
+    pub fn new_signed_transaction(
+        &self,
+        _state_context: ErgoStateContext,
+        _unspent_boxes: UnspentBoxes,
+        _data_inputs: TxDataInputs,
+        _outputs: TxOutputs,
+        _send_change_to: Address,
+        _min_change_value: u32,
+        _tx_fee_amount: u32,
+    ) -> Result<Transaction, JsValue> {
+        // not implemented, see https://github.com/ergoplatform/sigma-rust/issues/34
+        Err(JsValue::from_str("Not yet implemented"))
+    }
 }
diff --git a/sigma-wasm/src/utils.rs b/bindings/ergo-wallet-wasm/src/utils.rs
similarity index 100%
rename from sigma-wasm/src/utils.rs
rename to bindings/ergo-wallet-wasm/src/utils.rs
diff --git a/sigma-wasm/webpack.config.js b/bindings/ergo-wallet-wasm/webpack.config.js
similarity index 100%
rename from sigma-wasm/webpack.config.js
rename to bindings/ergo-wallet-wasm/webpack.config.js
diff --git a/ergo-wallet/Cargo.toml b/ergo-wallet/Cargo.toml
new file mode 100644
index 000000000..aab300320
--- /dev/null
+++ b/ergo-wallet/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "ergo-wallet"
+version = "0.1.0"
+authors = ["Denys Zadorozhnyi <denys@zadorozhnyi.com>"]
+edition = "2018"
+
+[lib]
+crate-type = ["cdylib", "rlib"]
+
+[dependencies]
+serde = { version = "1.0", features = ["derive"], optional = true }
+sigma-tree = { path = "../sigma-tree", features = ["with-serde"] }
+
+[features]
+with-serde = ["serde"]
diff --git a/ergo-wallet/src/ergo_state_context.rs b/ergo-wallet/src/ergo_state_context.rs
new file mode 100644
index 000000000..2cff90cad
--- /dev/null
+++ b/ergo-wallet/src/ergo_state_context.rs
@@ -0,0 +1,17 @@
+/// TBD
+pub struct ErgoStateContext();
+
+impl ErgoStateContext {
+    /// Dummy "empty" context
+    pub fn dummy() -> ErgoStateContext {
+        ErgoStateContext()
+    }
+
+    /// build from last block headers from node REST API "blocks/lastHeaders/{count}"
+    pub fn from_last_headers(_json_str: &str) -> Result<ErgoStateContext, ErgoStateContextError> {
+        todo!()
+    }
+}
+
+/// Errors on parsing and building from node REST API blocks/lastHeaders
+pub enum ErgoStateContextError {}
diff --git a/ergo-wallet/src/lib.rs b/ergo-wallet/src/lib.rs
new file mode 100644
index 000000000..c98c5d5b6
--- /dev/null
+++ b/ergo-wallet/src/lib.rs
@@ -0,0 +1,17 @@
+//! Ergo wallet
+
+// Coding conventions
+#![forbid(unsafe_code)]
+#![deny(non_upper_case_globals)]
+#![deny(non_camel_case_types)]
+#![deny(non_snake_case)]
+#![deny(unused_mut)]
+#![deny(dead_code)]
+#![deny(unused_imports)]
+#![deny(missing_docs)]
+
+mod ergo_state_context;
+mod secret_key;
+
+pub use ergo_state_context::*;
+pub use secret_key::*;
diff --git a/sigma-tree/src/chain/secret_key.rs b/ergo-wallet/src/secret_key.rs
similarity index 88%
rename from sigma-tree/src/chain/secret_key.rs
rename to ergo-wallet/src/secret_key.rs
index 0b34240f2..7d9edc1e6 100644
--- a/sigma-tree/src/chain/secret_key.rs
+++ b/ergo-wallet/src/secret_key.rs
@@ -1,4 +1,4 @@
-use crate::sigma_protocol::DlogProverInput;
+use sigma_tree::sigma_protocol::DlogProverInput;
 
 /// Types of secrets
 pub enum SecretKey {
diff --git a/sigma-tree-c/src/lib.rs b/sigma-tree-c/src/lib.rs
deleted file mode 100644
index 531265926..000000000
--- a/sigma-tree-c/src/lib.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-mod misc_c;
-
-pub use misc_c::*;
diff --git a/sigma-tree-c/src/misc_c.rs b/sigma-tree-c/src/misc_c.rs
deleted file mode 100644
index a0d2511b2..000000000
--- a/sigma-tree-c/src/misc_c.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-use std::os::raw::{c_int, c_longlong};
-
-#[no_mangle]
-pub extern "C" fn add_numbers(x: c_int, y: c_int) -> c_longlong {
-    x as i64 + y as i64
-}
diff --git a/sigma-tree/src/chain.rs b/sigma-tree/src/chain.rs
index cf96834ee..9a91b094b 100644
--- a/sigma-tree/src/chain.rs
+++ b/sigma-tree/src/chain.rs
@@ -8,7 +8,6 @@ mod data_input;
 mod ergo_box;
 mod input;
 mod prover_result;
-mod secret_key;
 mod token;
 mod transaction;
 
@@ -17,5 +16,4 @@ pub use box_id::*;
 pub use contract::*;
 pub use ergo_box::*;
 pub use input::*;
-pub use secret_key::*;
 pub use transaction::*;
diff --git a/sigma-tree/src/lib.rs b/sigma-tree/src/lib.rs
index b7e9cdd52..28bc96199 100644
--- a/sigma-tree/src/lib.rs
+++ b/sigma-tree/src/lib.rs
@@ -16,8 +16,8 @@ mod ecpoint;
 mod ergo_tree;
 mod eval;
 mod serialization;
-mod sigma_protocol;
 mod types;
 
 pub mod chain;
+pub mod sigma_protocol;
 pub use ergo_tree::*;
diff --git a/sigma-tree/src/sigma_protocol.rs b/sigma-tree/src/sigma_protocol.rs
index 7c6bd239e..b13bffb38 100644
--- a/sigma-tree/src/sigma_protocol.rs
+++ b/sigma-tree/src/sigma_protocol.rs
@@ -1,13 +1,17 @@
+//! Sigma protocols
 use k256::arithmetic::Scalar;
 
 use crate::{ecpoint::EcPoint, serialization::op_code::OpCode};
 use std::convert::TryInto;
 
+/// Secret key of discrete logarithm signature protocol
 pub struct DlogProverInput {
+    /// secret key value
     pub w: Scalar,
 }
 
 impl DlogProverInput {
+    /// generates random secret in the range [0, n), where n is DLog group order.
     pub fn random() -> DlogProverInput {
         let scalar = loop {
             // Generate a new secret key using the operating system's
@@ -29,6 +33,7 @@ impl DlogProverInput {
         DlogProverInput { w: scalar }
     }
 
+    /// public key of discrete logarithm signature protocol
     #[allow(dead_code)]
     fn public_image(&self) -> ProveDlog {
         // test it, see https://github.com/ergoplatform/sigma-rust/issues/38
@@ -37,7 +42,9 @@ impl DlogProverInput {
     }
 }
 
+/// Get public key for signature protocol
 pub trait PrivateInput {
+    /// public key
     fn public_image(&self) -> SigmaProofOfKnowledgeTree;
 }
 
@@ -48,12 +55,15 @@ impl PrivateInput for DlogProverInput {
     }
 }
 
+/// Construct a new SigmaBoolean value representing public key of discrete logarithm signature protocol.
 #[derive(PartialEq, Eq, Debug, Clone)]
 pub struct ProveDlog {
+    /// public key
     pub h: Box<EcPoint>,
 }
 
 impl ProveDlog {
+    /// create new public key
     pub fn new(ecpoint: EcPoint) -> ProveDlog {
         ProveDlog {
             h: Box::new(ecpoint),
@@ -61,6 +71,8 @@ impl ProveDlog {
     }
 }
 
+/// Construct a new SigmaProp value representing public key of Diffie Hellman signature protocol.
+/// Common input: (g,h,u,v)
 #[derive(PartialEq, Eq, Debug, Clone)]
 pub struct ProveDHTuple {
     gv: Box<EcPoint>,
@@ -69,19 +81,27 @@ pub struct ProveDHTuple {
     vv: Box<EcPoint>,
 }
 
+/// Sigma proposition
 #[derive(PartialEq, Eq, Debug, Clone)]
 pub enum SigmaProofOfKnowledgeTree {
+    /// public key of Diffie Hellman signature protocol
     ProveDHTuple(ProveDHTuple),
+    /// public key of discrete logarithm signature protocol
     ProveDlog(ProveDlog),
 }
 
+/// Algebraic data type of sigma proposition expressions
+/// Values of this type are used as values of SigmaProp type
 #[derive(PartialEq, Eq, Debug, Clone)]
 pub enum SigmaBoolean {
+    /// Sigma proposition
     ProofOfKnowledge(SigmaProofOfKnowledgeTree),
+    /// AND conjunction for sigma propositions
     CAND(Vec<SigmaBoolean>),
 }
 
 impl SigmaBoolean {
+    /// get OpCode for serialization
     pub fn op_code(&self) -> OpCode {
         match self {
             SigmaBoolean::ProofOfKnowledge(SigmaProofOfKnowledgeTree::ProveDlog(_)) => {
@@ -92,14 +112,17 @@ impl SigmaBoolean {
     }
 }
 
+/// Proposition which can be proven and verified by sigma protocol.
 #[derive(PartialEq, Eq, Debug, Clone)]
 pub struct SigmaProp(SigmaBoolean);
 
 impl SigmaProp {
+    /// create new sigma propostion from [`SigmaBoolean`] value
     pub fn new(sbool: SigmaBoolean) -> Self {
         SigmaProp { 0: sbool }
     }
 
+    /// get [`SigmaBoolean`] value
     pub fn value(&self) -> &SigmaBoolean {
         &self.0
     }


Test patch:
diff --git a/sigma-wasm/tests/index.js b/bindings/ergo-wallet-wasm/tests/index.js
similarity index 100%
rename from sigma-wasm/tests/index.js
rename to bindings/ergo-wallet-wasm/tests/index.js
diff --git a/bindings/ergo-wallet-wasm/tests/test_transaction.js b/bindings/ergo-wallet-wasm/tests/test_transaction.js
new file mode 100644
index 000000000..075882d9b
--- /dev/null
+++ b/bindings/ergo-wallet-wasm/tests/test_transaction.js
@@ -0,0 +1,27 @@
+import { expect } from 'chai';
+
+import {
+  Address, Wallet, UnspentBoxes, TxDataInputs, ErgoBoxCandidate, Contract,
+  TxOutputs, ErgoStateContext
+} from '../pkg/ergo_wallet_wasm';
+
+it('new signed transaction', async () => {
+
+  const recipient = Address.from_testnet_str('test');
+  const unspent_boxes = UnspentBoxes.from_boxes([]);
+  const tx_data_inputs = TxDataInputs.from_boxes([]);
+  const send_change_to = Address.from_testnet_str('');
+
+  let outbox = new ErgoBoxCandidate(1, 0, Contract.pay_to_address(recipient));
+  let tx_outputs = TxOutputs.from_boxes([outbox]);
+  let dummy_ctx = ErgoStateContext.dummy();
+  let wallet = Wallet.from_mnemonic("", "");
+  expect(() => wallet.new_signed_transaction(dummy_ctx,
+    unspent_boxes,
+    tx_data_inputs,
+    tx_outputs,
+    send_change_to,
+    1,
+    1)).to.throw("Not yet implemented");
+});
+
diff --git a/sigma-wasm/tests/transaction.rs b/bindings/ergo-wallet-wasm/tests/transaction.rs
similarity index 56%
rename from sigma-wasm/tests/transaction.rs
rename to bindings/ergo-wallet-wasm/tests/transaction.rs
index 5a409d991..4c61d1104 100644
--- a/sigma-wasm/tests/transaction.rs
+++ b/bindings/ergo-wallet-wasm/tests/transaction.rs
@@ -1,22 +1,32 @@
 //! Test suite for the Web and headless browsers.
 
-extern crate sigma_tree_wasm;
+extern crate ergo_wallet_wasm;
 extern crate wasm_bindgen_test;
-use sigma_tree_wasm::*;
+use ergo_wallet_wasm::*;
 use wasm_bindgen_test::*;
 
 wasm_bindgen_test_configure!(run_in_browser);
 
 #[wasm_bindgen_test]
 fn test_signed_p2pk_transaction() {
-    let tx_inputs = TxInputs::from_boxes(Box::new([]));
+    let tx_inputs = UnspentBoxes::from_boxes(Box::new([]));
+    let tx_data_inputs = TxDataInputs::from_boxes(Box::new([]));
     let send_change_to = Address::from_testnet_str("").expect("failed");
-    let sk = SecretKey::parse("").expect("failed");
     let recipient = Address::from_testnet_str("").expect("failed");
 
     let outbox = ErgoBoxCandidate::new(1, 0, Contract::pay_to_address(recipient));
     let out_boxes = [outbox.to_json().expect("failed")];
     let tx_outputs = TxOutputs::from_boxes(Box::new(out_boxes));
-    let res = new_signed_transaction(tx_inputs, tx_outputs, send_change_to, sk);
+    let dummy_ctx = ErgoStateContext::dummy();
+    let wallet = Wallet::from_mnemonic("", "");
+    let res = wallet.new_signed_transaction(
+        dummy_ctx,
+        tx_inputs,
+        tx_data_inputs,
+        tx_outputs,
+        send_change_to,
+        1,
+        1,
+    );
     assert!(res.is_err());
 }
diff --git a/sigma-wasm/tests/test_transaction.js b/sigma-wasm/tests/test_transaction.js
deleted file mode 100644
index 3b3f3a590..000000000
--- a/sigma-wasm/tests/test_transaction.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import { expect } from 'chai';
-
-import {TxInputs, SecretKey, ErgoBoxCandidate, Contract, TxOutputs} from '../pkg/sigma_tree_wasm';
-
-const sigma_rust = import('../pkg/sigma_tree_wasm');
-
-it('new transaction', async () => {
-  const {
-    Address,
-    new_signed_transaction,
-  } = await sigma_rust;
-
-  const recipient = Address.from_testnet_str('test');
-  const tx_inputs = TxInputs.from_boxes([]);
-  const send_change_to = Address.from_testnet_str('');
-  const sk = SecretKey.parse('');
-
-  let outbox = new ErgoBoxCandidate(1, 0, Contract.pay_to_address(recipient));
-  let tx_outputs = TxOutputs.from_boxes([outbox]);
-  expect(() => new_signed_transaction(tx_inputs, tx_outputs, send_change_to, sk)).to.throw();
-});
-