fix ups to emscripten build procedures; swapped cryptonote_crypto_EMSCRIPTEN with MyMoneroCoreCpp.(js,wasm), and had to introduce blocking to methods which use CNCrypto var due to new async Module init; updated Readme

pull/41/head
Paul Shapiro 6 years ago
parent 75a207d428
commit b529bdbeaa

3
.gitignore vendored

@ -2,11 +2,12 @@
node_modules/
coverage
.vscode
build
tests/emjs/MyMoneroCoreCpp.wasm
tests/emjs/MyMoneroCoreCpp.js
contrib/boost-sdk/bjam
contrib/boost-sdk/b2
contrib/boost-sdk/project-config.jam

@ -19,8 +19,7 @@ set(
#
src/index.cpp
src/submodules/monero-core-custom/crypto/crypto-ops.c
#
# TODO: hopefully pick up source from src/mymonero-core-cpp/src
src/submodules/monero-core-custom/crypto/crypto-ops-data.c
)
set(boost_DIR ${CMAKE_SOURCE_DIR}/build/boost)
@ -37,18 +36,6 @@ set_target_properties(
${boost_DIR}/lib/libboost_chrono.a
)
#
add_library(boost_context STATIC IMPORTED)
set_target_properties(
boost_context PROPERTIES IMPORTED_LOCATION
${boost_DIR}/lib/libboost_context.a
)
#
add_library(boost_exception STATIC IMPORTED)
set_target_properties(
boost_exception PROPERTIES IMPORTED_LOCATION
${boost_DIR}/lib/libboost_exception.a
)
#
add_library(boost_date_time STATIC IMPORTED)
set_target_properties(
boost_date_time PROPERTIES IMPORTED_LOCATION
@ -61,76 +48,16 @@ set_target_properties(
${boost_DIR}/lib/libboost_filesystem.a
)
#
add_library(boost_math_c99 STATIC IMPORTED)
set_target_properties(
boost_math_c99 PROPERTIES IMPORTED_LOCATION
${boost_DIR}/lib/libboost_math_c99.a
)
#
add_library(boost_math_c99f STATIC IMPORTED)
set_target_properties(
boost_math_c99f PROPERTIES IMPORTED_LOCATION
${boost_DIR}/lib/libboost_math_c99f.a
)
#
add_library(boost_math_c99l STATIC IMPORTED)
set_target_properties(
boost_math_c99l PROPERTIES IMPORTED_LOCATION
${boost_DIR}/lib/libboost_math_c99l.a
)
#
add_library(boost_math_tr1 STATIC IMPORTED)
set_target_properties(
boost_math_tr1 PROPERTIES IMPORTED_LOCATION
${boost_DIR}/lib/libboost_math_tr1.a
)
#
add_library(boost_math_tr1l STATIC IMPORTED)
set_target_properties(
boost_math_tr1l PROPERTIES IMPORTED_LOCATION
${boost_DIR}/lib/libboost_math_tr1l.a
)
#
add_library(boost_math_tr1f STATIC IMPORTED)
set_target_properties(
boost_math_tr1f PROPERTIES IMPORTED_LOCATION
${boost_DIR}/lib/libboost_math_tr1l.a
)
#
add_library(boost_random STATIC IMPORTED)
set_target_properties(
boost_random PROPERTIES IMPORTED_LOCATION
${boost_DIR}/lib/libboost_random.a
)
#
add_library(boost_locale STATIC IMPORTED)
set_target_properties(
boost_locale PROPERTIES IMPORTED_LOCATION
${boost_DIR}/lib/libboost_locale.a
)
#
add_library(boost_iostreams STATIC IMPORTED)
add_library(boost_program_options STATIC IMPORTED)
set_target_properties(
boost_iostreams PROPERTIES IMPORTED_LOCATION
${boost_DIR}/lib/libboost_iostreams.a
)
#
add_library(boost_signals STATIC IMPORTED)
set_target_properties(
boost_signals PROPERTIES IMPORTED_LOCATION
${boost_DIR}/lib/libboost_signals.a
)
#
add_library(boost_timer STATIC IMPORTED)
set_target_properties(
boost_timer PROPERTIES IMPORTED_LOCATION
${boost_DIR}/lib/libboost_timer.a
)
#
add_library(boost_container STATIC IMPORTED)
set_target_properties(
boost_container PROPERTIES IMPORTED_LOCATION
${boost_DIR}/lib/libboost_container.a
boost_program_options PROPERTIES IMPORTED_LOCATION
${boost_DIR}/lib/libboost_program_options.a
)
#
add_library(boost_regex STATIC IMPORTED)
@ -145,6 +72,12 @@ set_target_properties(
${boost_DIR}/lib/libboost_serialization.a
)
#
add_library(boost_signals STATIC IMPORTED)
set_target_properties(
boost_signals PROPERTIES IMPORTED_LOCATION
${boost_DIR}/lib/libboost_signals.a
)
#
add_library(boost_system STATIC IMPORTED)
set_target_properties(
boost_system PROPERTIES IMPORTED_LOCATION
@ -157,6 +90,12 @@ set_target_properties(
${boost_DIR}/lib/libboost_thread.a
)
#
add_library(boost_timer STATIC IMPORTED)
set_target_properties(
boost_timer PROPERTIES IMPORTED_LOCATION
${boost_DIR}/lib/libboost_timer.a
)
#
add_library(boost_wserialization STATIC IMPORTED)
set_target_properties(
boost_wserialization PROPERTIES IMPORTED_LOCATION
@ -171,7 +110,7 @@ set(
"-Wall -std=c++11 -s MODULARIZE=1 -s WASM=1 -s ASSERTIONS=1 \
--bind \
-s 'EXPORT_NAME=\"MyMoneroCoreCpp\"' \
-s EXPORTED_FUNCTIONS='[\"_sc_reduce32\"]' \
-s EXPORTED_FUNCTIONS='[\"_sc_reduce\", \"_sc_reduce32\", \"_sc_check\", \"_sc_add\", \"_ge_fromfe_frombytes_vartime\", \"_ge_mul8\", \"_ge_p1p1_to_p3\", \"_ge_p3_tobytes\", \"_ge_scalarmult\", \"_ge_tobytes\", \"_sc_sub\", \"_sc_mulsub\", \"_ge_scalarmult_base\", \"_sc_0\", \"_ge_double_scalarmult_base_vartime\", \"_ge_double_scalarmult_precomp_vartime\", \"_ge_frombytes_vartime\", \"_ge_dsm_precomp\"]' \
-s EXTRA_EXPORTED_RUNTIME_METHODS='[\"ccall\", \"cwrap\"]'"#"-s SAFE_HEAP=1 --bind -O3 -s LEGACY_GL_EMULATION=0 -s GL_UNSAFE_OPTS=0 --pre-js pre-module.js --post-js post-module.js -s GL_ASSERTIONS=1 -s INVOKE_RUN=0 -s USE_WEBGL2=1 -s FULL_ES3=1 -s USE_GLFW=3 -s OFFSCREENCANVAS_SUPPORT=1 --preload-file shaders --preload-file extern --use-preload-plugins"
)
@ -182,44 +121,24 @@ add_executable(
)
set_target_properties(MyMoneroCoreCpp PROPERTIES LINK_FLAGS "${EMCC_LINKER_FLAGS}")
# set_target_properties(MyMoneroCoreCpp PROPERTIES SUFFIX ".bc")
# target_link_libraries(
# MyMoneroCoreCpp
# #
# OpenSSL::SSL
# ${Boost_LIBRARIES}
# )
target_link_libraries(
MyMoneroCoreCpp
#
# OpenSSL::SSL
#
boost_atomic
boost_chrono
boost_context
boost_date_time
boost_exception
boost_filesystem
boost_container
# boost_graph
boost_iostreams
boost_locale
boost_math_c99
boost_math_c99f
boost_math_c99l
boost_math_tr1
boost_math_tr1f
boost_math_tr1l
# boost_prg_exec_monitor
# boost_program_options
boost_random
boost_program_options
boost_regex
boost_serialization
boost_signals
boost_system
# boost_test_exec_monitor
boost_thread
boost_timer
# boost_unit_test_framework
# boost_wave
boost_wserialization
${log-lib}
)

@ -4,8 +4,9 @@
1. Legal
2. What's in This Repo?
3. Library Roadmap
4. Library API Documentation
3. Building MyMoneroCoreCpp
4. Library Roadmap
5. Library API Documentation
### Contributing
@ -21,19 +22,44 @@ See `LICENSE.txt` for license.
All source code copyright © 2014-2018 by MyMonero. All rights reserved.
## What's in This Repo?
This repository holds the Javascript source code for the Monero/CryptoNote cryptography and protocols, plus lightwallet functions which power the official [MyMonero](https://www.mymonero.com) apps.
There is also a chain of build scripts which is capable of building a JS module by transpiling a subset of Monero source code via emscripten, which relies upon static boost libs, for which there is also a script for building from source.
### Contents
* `monero_utils` contains Monero- and MyMonero-specific implementations, wrappers, and declarations.
* `cryptonote_utils` contains the MyMonero JS implementations for the underlying cryptography behind Monero.
* `cryptonote_utils` contains the MyMonero JS implementations for the underlying cryptography behind Monero.
* `cryptonote_utils/MyMoneroCoreCpp.(js,wasm)` are produced by transpiling Monero core C++ code to JS via Emscripten (See *Building MyMoneroCoreCpp*). A Module instance is managed by `cryptonote_utils/cryptonote_utils.js`.
* This readme is located at `README.md`, and the license is located at `LICENSE.txt`.
## Building MyMoneroCoreCpp
### Install Emscripten SDK
Ensure you've [properly installed Emscripten](http://kripken.github.io/emscripten-site/docs/getting_started/downloads.html) and exposed the Emscripten executables in your PATH, e.g.:
source ./emsdk_env.sh
### Boost for Emscripten
*Depends upon:* Emscripten SDK
Download a copy of the contents of the Boost source into `./contrib/boost-sdk/`.
* Execute `bin/build-boost-emscripten.sh`
### Emscripten Module
*Depends upon:* Emscripten SDK, Boost for Emscripten
* Execute `npm run-script build-emcpp`
## Library Roadmap
* Investigate replacing entire implementation with bindings to lightwallet API in official Monero core wallet C++

@ -9,22 +9,17 @@ SRC_PATH="$(pwd)/$SRC_DIR"
INSTALL_PATH="$(pwd)/$INSTALL_DIR"
JAM_CONFIG_PATH="$(pwd)/configs/$PLATFORM.jam"
export AR="$EMSCRIPTEN_PATH/emar"
# <ranlib>${EMSCRIPTEN_PATH}/emranlib
# <linker>${EMSCRIPTEN_PATH}/emlink
if [ ! -d "$SRC_PATH" ]; then
echo "SOURCE NOT FOUND!"
exit 1
fi
if [ -z "$EMSCRIPTEN_PATH" ]; then
echo "EMSCRIPTEN_PATH MUST BE DEFINED!"
if [ -z "$EMSCRIPTEN" ]; then
echo "EMSCRIPTEN MUST BE DEFINED!"
exit -1
fi
cd $EMSCRIPTEN_PATH; ./embuilder.py build zlib
cd $EMSCRIPTEN; ./embuilder.py build zlib
# ---
@ -40,7 +35,7 @@ export NO_BZIP2=1 #bc it's supplied by emscripten but b2 will fail to find it
./bootstrap.sh \
--with-libraries=atomic,chrono,container,context,date_time,iostreams,locale,signals,timer,filesystem,regex,serialization,system,thread,math,random,exception \
--with-libraries=atomic,signals,timer,system,filesystem,thread,date_time,chrono,regex,serialization,program_options,locale \
2>&1
if [ $? != 0 ]; then

@ -6,16 +6,16 @@
#
import os ;
local EMSCRIPTEN_PATH = [ os.environ EMSCRIPTEN_PATH ] ;
local EMSCRIPTEN = [ os.environ EMSCRIPTEN ] ;
using clang : emscripten
:
emcc -v -s USE_ZLIB=1
:
<root>$(EMSCRIPTEN_PATH)
<archiver>$(EMSCRIPTEN_PATH)/emar
<ranlib>$(EMSCRIPTEN_PATH)/emranlib
<linker>$(EMSCRIPTEN_PATH)/emlink
<root>$(EMSCRIPTEN)
<archiver>$(EMSCRIPTEN)/emar
<ranlib>$(EMSCRIPTEN)/emranlib
<linker>$(EMSCRIPTEN)/emlink
<cxxflags>-std=c++11
;

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

@ -33,7 +33,18 @@
// v--- These should maybe be injected into a context and supplied to currencyConfig for future platforms
const JSBigInt = require("./biginteger").BigInteger;
const cnBase58 = require("./cryptonote_base58").cnBase58;
const CNCrypto = require("./cryptonote_crypto_EMSCRIPTEN");
var _CNCrypto = undefined; // undefined -> cause 'early' calls to CNCrypto to throw exception
require("./MyMoneroCoreCpp")().then(function(Module)
{
_CNCrypto = Module;
});
function loaded_CNCrypto()
{ // CAUTION: calling this method blocks until _CNCrypto is loaded
while (typeof _CNCrypto === 'undefined' || !_CNCrypto) {
// console.log("Blocking until MyMoneroCoreCpp is loaded.")
}
return _CNCrypto;
}
const mnemonic = require("./mnemonic");
const nacl = require("./nacl-fast-cn");
const sha3 = require("./sha3");
@ -371,6 +382,7 @@ var cnUtil = function(currencyConfig) {
if (input.length !== 64) {
throw "Invalid input length";
}
const CNCrypto = loaded_CNCrypto();
var mem = CNCrypto._malloc(64);
CNCrypto.HEAPU8.set(input, mem);
CNCrypto.ccall("sc_reduce", "void", ["number"], [mem]);
@ -384,6 +396,7 @@ var cnUtil = function(currencyConfig) {
if (input.length !== 32) {
throw "Invalid input length";
}
const CNCrypto = loaded_CNCrypto();
var mem = CNCrypto._malloc(32);
CNCrypto.HEAPU8.set(input, mem);
CNCrypto.ccall("sc_reduce32", "void", ["number"], [mem]);
@ -412,6 +425,7 @@ var cnUtil = function(currencyConfig) {
if (input.length !== 32) {
throw "Invalid input length";
}
const CNCrypto = loaded_CNCrypto();
var input_mem = CNCrypto._malloc(KEY_SIZE);
CNCrypto.HEAPU8.set(input, input_mem);
var ge_p3 = CNCrypto._malloc(STRUCT_SIZES.GE_P3);
@ -444,6 +458,7 @@ var cnUtil = function(currencyConfig) {
}
var pub_b = hextobin(pub);
var sec_b = hextobin(sec);
const CNCrypto = loaded_CNCrypto();
var pub_m = CNCrypto._malloc(KEY_SIZE);
CNCrypto.HEAPU8.set(pub_b, pub_m);
var sec_m = CNCrypto._malloc(KEY_SIZE);
@ -540,6 +555,7 @@ var cnUtil = function(currencyConfig) {
if (outlen <= 0) {
throw "Invalid output length";
}
const CNCrypto = loaded_CNCrypto();
var input_mem = CNCrypto._malloc(inlen);
CNCrypto.HEAPU8.set(input, input_mem);
var out_mem = CNCrypto._malloc(outlen);
@ -667,6 +683,7 @@ var cnUtil = function(currencyConfig) {
}
var pub_b = hextobin(pub);
var sec_b = hextobin(sec);
const CNCrypto = loaded_CNCrypto();
var pub_m = CNCrypto._malloc(KEY_SIZE);
CNCrypto.HEAPU8.set(pub_b, pub_m);
var sec_m = CNCrypto._malloc(KEY_SIZE);
@ -718,6 +735,7 @@ var cnUtil = function(currencyConfig) {
if (derivation.length !== 64 || sec.length !== 64) {
throw "Invalid input length!";
}
const CNCrypto = loaded_CNCrypto();
var scalar_m = CNCrypto._malloc(STRUCT_SIZES.EC_SCALAR);
var scalar_b = hextobin(
this.derivation_to_scalar(derivation, out_index),
@ -746,6 +764,7 @@ var cnUtil = function(currencyConfig) {
if (derivation.length !== 64 || pub.length !== 64) {
throw "Invalid input length!";
}
const CNCrypto = loaded_CNCrypto();
var derivation_m = CNCrypto._malloc(KEY_SIZE);
var derivation_b = hextobin(derivation);
CNCrypto.HEAPU8.set(derivation_b, derivation_m);
@ -810,6 +829,7 @@ var cnUtil = function(currencyConfig) {
if (key.length !== KEY_SIZE * 2) {
throw "Invalid input length";
}
const CNCrypto = loaded_CNCrypto();
var h_m = CNCrypto._malloc(HASH_SIZE);
var point_m = CNCrypto._malloc(STRUCT_SIZES.GE_P2);
var point2_m = CNCrypto._malloc(STRUCT_SIZES.GE_P1P1);
@ -847,6 +867,7 @@ var cnUtil = function(currencyConfig) {
if (key.length !== KEY_SIZE * 2) {
throw "Invalid input length";
}
const CNCrypto = loaded_CNCrypto();
var h_m = CNCrypto._malloc(HASH_SIZE);
var point_m = CNCrypto._malloc(STRUCT_SIZES.GE_P2);
var point2_m = CNCrypto._malloc(STRUCT_SIZES.GE_P1P1);
@ -892,6 +913,7 @@ var cnUtil = function(currencyConfig) {
if (!pub || !sec || pub.length !== 64 || sec.length !== 64) {
throw "Invalid input length";
}
const CNCrypto = loaded_CNCrypto();
var pub_m = CNCrypto._malloc(KEY_SIZE);
var sec_m = CNCrypto._malloc(KEY_SIZE);
CNCrypto.HEAPU8.set(hextobin(pub), pub_m);
@ -1021,6 +1043,7 @@ var cnUtil = function(currencyConfig) {
//adds two points together, order does not matter
/*this.ge_add2 = function(point1, point2) {
const CNCrypto = loaded_CNCrypto();
var point1_m = CNCrypto._malloc(KEY_SIZE);
var point2_m = CNCrypto._malloc(KEY_SIZE);
var point1_m2 = CNCrypto._malloc(STRUCT_SIZES.GE_P3);
@ -1071,6 +1094,7 @@ var cnUtil = function(currencyConfig) {
if (scalar1.length !== 64 || scalar2.length !== 64) {
throw "Invalid input length!";
}
const CNCrypto = loaded_CNCrypto();
var scalar1_m = CNCrypto._malloc(STRUCT_SIZES.EC_SCALAR);
var scalar2_m = CNCrypto._malloc(STRUCT_SIZES.EC_SCALAR);
CNCrypto.HEAPU8.set(hextobin(scalar1), scalar1_m);
@ -1097,6 +1121,7 @@ var cnUtil = function(currencyConfig) {
if (scalar1.length !== 64 || scalar2.length !== 64) {
throw "Invalid input length!";
}
const CNCrypto = loaded_CNCrypto();
var scalar1_m = CNCrypto._malloc(STRUCT_SIZES.EC_SCALAR);
var scalar2_m = CNCrypto._malloc(STRUCT_SIZES.EC_SCALAR);
CNCrypto.HEAPU8.set(hextobin(scalar1), scalar1_m);
@ -1143,6 +1168,7 @@ var cnUtil = function(currencyConfig) {
) {
throw "bad scalar";
}
const CNCrypto = loaded_CNCrypto();
var sec_m = CNCrypto._malloc(KEY_SIZE);
CNCrypto.HEAPU8.set(hextobin(sec), sec_m);
var sigc_m = CNCrypto._malloc(KEY_SIZE);
@ -1167,6 +1193,7 @@ var cnUtil = function(currencyConfig) {
//res = aB + cG; argument names copied from the signature implementation
/*this.ge_double_scalarmult_base_vartime = function(sigc, pub, sigr) {
const CNCrypto = loaded_CNCrypto();
var pub_m = CNCrypto._malloc(KEY_SIZE);
var pub2_m = CNCrypto._malloc(STRUCT_SIZES.GE_P3);
CNCrypto.HEAPU8.set(hextobin(pub), pub_m);
@ -1210,6 +1237,7 @@ var cnUtil = function(currencyConfig) {
//res = a * Hp(B) + c*D
//res = sigr * Hp(pub) + sigc * k_image; argument names also copied from the signature implementation; note precomp AND hash_to_ec are done internally!!
/*this.ge_double_scalarmult_postcomp_vartime = function(sigr, pub, sigc, k_image) {
const CNCrypto = loaded_CNCrypto();
var image_m = CNCrypto._malloc(STRUCT_SIZES.KEY_IMAGE);
CNCrypto.HEAPU8.set(hextobin(k_image), image_m);
var image_unp_m = CNCrypto._malloc(STRUCT_SIZES.GE_P3);
@ -2362,6 +2390,7 @@ var cnUtil = function(currencyConfig) {
if (real_index >= keys.length || real_index < 0) {
throw "real_index is invalid";
}
const CNCrypto = loaded_CNCrypto();
var _ge_tobytes = CNCrypto.cwrap("ge_tobytes", "void", [
"number",
"number",

@ -10,8 +10,7 @@
"scripts": {
"format": "find . -name '*.js*' | xargs prettier --write --config ./.prettierrc --config-precedence file-override",
"build-emcpp": "mkdir -p build && cd build && emconfigure cmake .. && emmake cmake --build . && emmake make .",
"_build-test-emjs": "npm run-script build-emcpp && cp build/MyMoneroCoreCpp.js tests/emjs/ && cp build/MyMoneroCoreCpp.wasm tests/emjs/",
"run-test-emjs": "npm run-script _build-test-emjs && cd tests/emjs && ../../node_modules/jest/bin/jest.js MyMoneroCoreCpp.spec.js",
"archive-emcpp": "npm run-script build-emcpp && cp build/MyMoneroCoreCpp.js cryptonote_utils/ && cp build/MyMoneroCoreCpp.wasm cryptonote_utils/",
"test": "jest",
"test:coverage": "jest --coverage"
},

@ -19,6 +19,6 @@ extern "C"
{ // C -> JS
}
int main() {
printf("hello, world!\n");
// printf("hello, world!\n");
return 0;
}

@ -0,0 +1,41 @@
// Copyright (c) 2014-2018, MyMonero.com
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"use strict";
//
const dummy_test_utils = require("./dummy-test-utils.js");
const dummy_cnUtils_instance = require("./dummy-cnutils").cnUtil()
console.log("dummy_test_utils.Module", dummy_test_utils.Module)
dummy_test_utils.OnceModuleReady(
function(Module)
{
console.log("Module", Module)
}
)

@ -27,7 +27,7 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"use strict";
const MyMoneroCoreCpp = require("./MyMoneroCoreCpp.js");
const MyMoneroCoreCpp = require("../../cryptonote_utils/MyMoneroCoreCpp.js");
var public_key =
"904e49462268d771cc1649084c35aa1296bfb214880fe2e7f373620a3e2ba597";
@ -53,6 +53,7 @@ exports.OnceModuleReady = function(fn)
MyMoneroCoreCpp().then(function(thisModule)
{
Module = thisModule
exports.Module = Module
{
for (let fn of moduleReadyFns) {
fn(Module)

@ -0,0 +1 @@
const mymonero = require("../../");
Loading…
Cancel
Save