// 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.
// Original Author: Lucas Jones
// Modified to remove jQuery dep and support modular inclusion of deps by Paul Shapiro (2016)
// Modified to add RingCT support by luigi1111 (2017)
//
// v--- These should maybe be injected into a context and supplied to currencyConfig for future platforms
const JSBigInt = require ( "../cryptonote_utils/biginteger" ) . BigInteger ;
const nettype _utils = require ( "../cryptonote_utils/nettype" ) ;
const monero _config = require ( './monero_config' ) ;
const currency _amount _format _utils = require ( "../cryptonote_utils/money_format_utils" ) ( monero _config ) ;
//
function ret _val _boolstring _to _bool ( boolstring )
{
if ( typeof boolstring !== "string" ) {
throw "ret_val_boolstring_to_bool expected string input"
}
if ( boolstring === "true" ) {
return true
} else if ( boolstring === "false" ) {
return false
}
throw "ret_val_boolstring_to_bool given illegal input"
}
function api _safe _wordset _name ( wordset _name )
{
// convert all lowercase, legacy values to core-cpp compatible
if ( wordset _name == "english" ) {
return "English"
} else if ( wordset _name == "spanish" ) {
return "Español"
} else if ( wordset _name == "portuguese" ) {
return "Português"
} else if ( wordset _name == "japanese" ) {
return "日本語"
}
return wordset _name // must be a value returned by core-cpp
}
//
class MyMoneroCoreBridge
{
constructor ( this _Module )
{
this . Module = this _Module ;
}
//
//
is _subaddress ( addr , nettype ) {
const args =
{
address : addr ,
nettype _string : nettype _utils . nettype _to _API _string ( nettype )
} ;
const args _str = JSON . stringify ( args ) ;
const ret _string = this . Module . is _subaddress ( args _str ) ;
const ret = JSON . parse ( ret _string ) ;
if ( typeof ret . err _msg !== 'undefined' && ret . err _msg ) {
return { err _msg : ret . err _msg }
}
return ret _val _boolstring _to _bool ( ret . retVal ) ;
}
is _integrated _address ( addr , nettype ) {
const args =
{
address : addr ,
nettype _string : nettype _utils . nettype _to _API _string ( nettype )
} ;
const args _str = JSON . stringify ( args ) ;
const ret _string = this . Module . is _integrated _address ( args _str ) ;
const ret = JSON . parse ( ret _string ) ;
if ( typeof ret . err _msg !== 'undefined' && ret . err _msg ) {
return { err _msg : ret . err _msg }
}
return ret _val _boolstring _to _bool ( ret . retVal ) ;
}
new _payment _id ( ) {
const args = { } ;
const args _str = JSON . stringify ( args ) ;
const ret _string = this . Module . new _payment _id ( args _str ) ;
const ret = JSON . parse ( ret _string ) ;
if ( typeof ret . err _msg !== 'undefined' && ret . err _msg ) {
return { err _msg : ret . err _msg }
}
return ret . retVal ;
}
new _ _int _addr _from _addr _and _short _pid (
address ,
short _pid ,
nettype
) {
if ( ! short _pid || short _pid . length != 16 ) {
return { err _msg : "expected valid short_pid" } ;
}
const args =
{
address : address ,
short _pid : short _pid ,
nettype _string : nettype _utils . nettype _to _API _string ( nettype )
} ;
const args _str = JSON . stringify ( args ) ;
const ret _string = this . Module . new _integrated _address ( args _str ) ;
const ret = JSON . parse ( ret _string ) ;
if ( typeof ret . err _msg !== 'undefined' && ret . err _msg ) {
return { err _msg : ret . err _msg }
}
return ret . retVal ;
}
decode _address ( address , nettype )
{
const args =
{
address : address ,
nettype _string : nettype _utils . nettype _to _API _string ( nettype )
} ;
const args _str = JSON . stringify ( args ) ;
const ret _string = this . Module . decode _address ( args _str ) ;
const ret = JSON . parse ( ret _string ) ;
if ( typeof ret . err _msg !== 'undefined' && ret . err _msg ) {
return { err _msg : ret . err _msg }
}
return {
spend : ret . pub _spendKey _string ,
view : ret . pub _viewKey _string ,
intPaymentId : ret . paymentID _string , // may be undefined
isSubaddress : ret _val _boolstring _to _bool ( ret . isSubaddress )
}
}
newly _created _wallet (
locale _language _code ,
nettype
) {
const args =
{
locale _language _code : locale _language _code , // NOTE: this function takes the locale, not the wordset name
nettype _string : nettype _utils . nettype _to _API _string ( nettype )
} ;
const args _str = JSON . stringify ( args ) ;
const ret _string = this . Module . newly _created _wallet ( args _str ) ;
const ret = JSON . parse ( ret _string ) ;
if ( typeof ret . err _msg !== 'undefined' && ret . err _msg ) {
return { err _msg : ret . err _msg }
}
return { // calling these out so as to provide a stable ret val interface
mnemonic _string : ret . mnemonic _string ,
mnemonic _language : ret . mnemonic _language ,
sec _seed _string : ret . sec _seed _string ,
address _string : ret . address _string ,
pub _viewKey _string : ret . pub _viewKey _string ,
sec _viewKey _string : ret . sec _viewKey _string ,
pub _spendKey _string : ret . pub _spendKey _string ,
sec _spendKey _string : ret . sec _spendKey _string
} ;
}
are _equal _mnemonics ( a , b ) {
const args =
{
a : a ,
b : b
} ;
const args _str = JSON . stringify ( args ) ;
const ret _string = this . Module . are _equal _mnemonics ( args _str ) ;
const ret = JSON . parse ( ret _string ) ;
if ( typeof ret . err _msg !== 'undefined' && ret . err _msg ) {
return { err _msg : ret . err _msg }
}
return ret _val _boolstring _to _bool ( ret . retVal ) ;
}
mnemonic _from _seed (
seed _string ,
wordset _name
) {
const args =
{
seed _string : seed _string ,
wordset _name : api _safe _wordset _name ( wordset _name )
} ;
const args _str = JSON . stringify ( args ) ;
const ret _string = this . Module . mnemonic _from _seed ( args _str ) ;
const ret = JSON . parse ( ret _string ) ;
if ( typeof ret . err _msg !== 'undefined' && ret . err _msg ) {
return { err _msg : ret . err _msg } // TODO: maybe return this somehow
}
return ret . retVal ;
}
seed _and _keys _from _mnemonic (
mnemonic _string ,
nettype
) {
const args =
{
mnemonic _string : mnemonic _string ,
nettype _string : nettype _utils . nettype _to _API _string ( nettype )
} ;
const args _str = JSON . stringify ( args ) ;
const ret _string = this . Module . seed _and _keys _from _mnemonic ( args _str ) ;
const ret = JSON . parse ( ret _string ) ;
if ( typeof ret . err _msg !== 'undefined' && ret . err _msg ) {
return { err _msg : ret . err _msg }
}
return { // calling these out so as to provide a stable ret val interface
sec _seed _string : ret . sec _seed _string ,
mnemonic _language : ret . mnemonic _language ,
address _string : ret . address _string ,
pub _viewKey _string : ret . pub _viewKey _string ,
sec _viewKey _string : ret . sec _viewKey _string ,
pub _spendKey _string : ret . pub _spendKey _string ,
sec _spendKey _string : ret . sec _spendKey _string
} ;
}
validate _components _for _login (
address _string ,
sec _viewKey _string ,
sec _spendKey _string ,
seed _string ,
nettype
) {
const args =
{
address _string : address _string ,
sec _viewKey _string : sec _viewKey _string ,
sec _spendKey _string : sec _spendKey _string ,
seed _string : seed _string ,
nettype _string : nettype _utils . nettype _to _API _string ( nettype )
} ;
const args _str = JSON . stringify ( args ) ;
const ret _string = this . Module . validate _components _for _login ( args _str ) ;
const ret = JSON . parse ( ret _string ) ;
if ( typeof ret . err _msg !== 'undefined' && ret . err _msg ) {
return { err _msg : ret . err _msg }
}
return { // calling these out so as to provide a stable ret val interface
isValid : ret _val _boolstring _to _bool ( ret . isValid ) ,
isInViewOnlyMode : ret _val _boolstring _to _bool ( ret . isInViewOnlyMode ) ,
pub _viewKey _string : ret . pub _viewKey _string ,
pub _spendKey _string : ret . pub _spendKey _string
} ;
}
address _and _keys _from _seed (
seed _string ,
nettype
) {
const args =
{
seed _string : seed _string ,
nettype _string : nettype _utils . nettype _to _API _string ( nettype )
} ;
const args _str = JSON . stringify ( args ) ;
const ret _string = this . Module . address _and _keys _from _seed ( args _str ) ;
const ret = JSON . parse ( ret _string ) ;
if ( typeof ret . err _msg !== 'undefined' && ret . err _msg ) {
return { err _msg : ret . err _msg }
}
return { // calling these out so as to provide a stable ret val interface
address _string : ret . address _string ,
pub _viewKey _string : ret . pub _viewKey _string ,
sec _viewKey _string : ret . sec _viewKey _string ,
pub _spendKey _string : ret . pub _spendKey _string ,
sec _spendKey _string : ret . sec _spendKey _string
} ;
}
generate _key _image (
tx _pub ,
view _sec ,
spend _pub ,
spend _sec ,
output _index
) {
if ( tx _pub . length !== 64 ) {
return { err _msg : "Invalid tx_pub length" } ;
}
if ( view _sec . length !== 64 ) {
return { err _msg : "Invalid view_sec length" } ;
}
if ( spend _pub . length !== 64 ) {
return { err _msg : "Invalid spend_pub length" } ;
}
if ( spend _sec . length !== 64 ) {
return { err _msg : "Invalid spend_sec length" } ;
}
const args =
{
sec _viewKey _string : view _sec ,
sec _spendKey _string : spend _sec ,
pub _spendKey _string : spend _pub ,
tx _pub _key : tx _pub ,
out _index : "" + output _index
} ;
const args _str = JSON . stringify ( args ) ;
const ret _string = this . Module . generate _key _image ( args _str ) ;
const ret = JSON . parse ( ret _string ) ;
if ( typeof ret . err _msg !== 'undefined' && ret . err _msg ) {
return { err _msg : ret . err _msg } ;
}
return ret . retVal ;
}
generate _key _derivation (
pub ,
sec ,
) {
const args =
{
pub : pub ,
sec : sec ,
} ;
const args _str = JSON . stringify ( args ) ;
const ret _string = this . Module . generate _key _derivation ( args _str ) ;
const ret = JSON . parse ( ret _string ) ;
if ( typeof ret . err _msg !== 'undefined' && ret . err _msg ) {
return { err _msg : ret . err _msg } ;
}
return ret . retVal ;
}
derive _public _key ( derivation , out _index , pub )
{
const args =
{
pub : pub ,
derivation : derivation ,
out _index : out _index ,
} ;
const args _str = JSON . stringify ( args ) ;
const ret _string = this . Module . derive _public _key ( args _str ) ;
const ret = JSON . parse ( ret _string ) ;
if ( typeof ret . err _msg !== 'undefined' && ret . err _msg ) {
return { err _msg : ret . err _msg } ;
}
return ret . retVal ;
}
derive _subaddress _public _key (
output _key ,
derivation ,
out _index
) {
const args =
{
output _key : output _key ,
derivation : derivation ,
out _index : "" + out _index , // must be passed as string
} ;
const args _str = JSON . stringify ( args ) ;
const ret _string = this . Module . derive _subaddress _public _key ( args _str ) ;
const ret = JSON . parse ( ret _string ) ;
if ( typeof ret . err _msg !== 'undefined' && ret . err _msg ) {
return { err _msg : ret . err _msg } ;
}
return ret . retVal ;
}
decodeRct ( rv , sk , i )
{
const ecdhInfo = [ ] ; // should obvs be plural but just keeping exact names in-tact
for ( var j = 0 ; j < rv . outPk . length ; j ++ ) {
var this _ecdhInfo = rv . ecdhInfo [ j ] ;
ecdhInfo . push ( {
mask : this _ecdhInfo . mask ,
amount : this _ecdhInfo . amount
} )
}
const outPk = [ ] ;
for ( var j = 0 ; j < rv . outPk . length ; j ++ ) {
var this _outPk _mask = null ;
var this _outPk = rv . outPk [ j ] ;
if ( typeof this _outPk === 'string' ) {
this _outPk _mask = this _outPk ;
} else if ( typeof this _outPk === "object" ) {
this _outPk _mask = this _outPk . mask ;
}
if ( this _outPk _mask == null ) {
return { err _msg : "Couldn't locate outPk mask value" }
}
outPk . push ( {
mask : this _outPk _mask
} )
}
const args =
{
i : "" + i , // must be passed as string
sk : sk ,
rv : {
type : "" + rv . type /*must be string*/ , // e.g. 1, 3 ... corresponding to rct::RCTType* in rctSigs.cpp
ecdhInfo : ecdhInfo ,
outPk : outPk
}
} ;
const args _str = JSON . stringify ( args ) ;
const ret _string = this . Module . decodeRct ( args _str ) ;
const ret = JSON . parse ( ret _string ) ;
if ( typeof ret . err _msg !== 'undefined' && ret . err _msg ) {
return { err _msg : ret . err _msg }
}
return { // calling these out so as to provide a stable ret val interface
amount : ret . amount , // string
mask : ret . mask ,
} ;
}
estimate _rct _tx _size ( n _inputs , mixin , n _outputs , optl _ _extra _size , optl _ _bulletproof )
{
const args =
{
n _inputs : "" + n _inputs ,
mixin : "" + mixin ,
n _outputs : "" + n _outputs ,
extra _size : "" + ( typeof optl _ _extra _size !== 'undefined' && optl _ _extra _size ? optl _ _extra _size : 0 ) ,
bulletproof : "" + ( optl _ _bulletproof == false ? false : true ) /* default true */ ,
} ;
const args _str = JSON . stringify ( args ) ;
const ret _string = this . Module . estimate _rct _tx _size ( args _str ) ;
const ret = JSON . parse ( ret _string ) ;
if ( typeof ret . err _msg !== 'undefined' && ret . err _msg ) {
return { err _msg : ret . err _msg } // TODO: maybe return this somehow
}
return parseInt ( ret . retVal ) ; // small enough to parse
}
calculate _fee ( fee _per _kb _ _string , num _bytes , fee _multiplier )
{
const args =
{
fee _per _kb : fee _per _kb _ _string ,
num _bytes : "" + num _bytes ,
fee _multiplier : "" + fee _multiplier
} ;
const args _str = JSON . stringify ( args ) ;
const ret _string = this . Module . calculate _fee ( args _str ) ;
const ret = JSON . parse ( ret _string ) ;
if ( typeof ret . err _msg !== 'undefined' && ret . err _msg ) {
return { err _msg : ret . err _msg } // TODO: maybe return this somehow
}
return ret . retVal ; // this is a string - pass it to new JSBigInt(…)
}
estimated _tx _network _fee ( fee _per _kb _ _string , priority )
{
const args =
{
fee _per _kb : fee _per _kb _ _string ,
priority : "" + priority ,
} ;
const args _str = JSON . stringify ( args ) ;
const ret _string = this . Module . estimated _tx _network _fee ( args _str ) ;
const ret = JSON . parse ( ret _string ) ;
if ( typeof ret . err _msg !== 'undefined' && ret . err _msg ) {
return { err _msg : ret . err _msg } // TODO: maybe return this somehow
}
return ret . retVal ; // this is a string - pass it to new JSBigInt(…)
}
create _signed _transaction (
from _address _string ,
sec _keys ,
to _address _string ,
outputs ,
mix _outs ,
fake _outputs _count ,
serialized _ _sending _amount ,
serialized _ _change _amount ,
serialized _ _fee _amount , // string amount
payment _id ,
unlock _time ,
rct ,
nettype
) {
return this . create _signed _transaction _ _nonIPCsafe (
from _address _string ,
sec _keys ,
to _address _string ,
outputs ,
mix _outs ,
fake _outputs _count ,
new JSBigInt ( serialized _ _sending _amount ) ,
new JSBigInt ( serialized _ _change _amount ) ,
new JSBigInt ( serialized _ _fee _amount ) , // only to be deserialized again is a bit silly but this at least exposes a JSBigInt API for others
payment _id ,
unlock _time ,
rct ,
nettype
) ;
}
create _signed _transaction _ _nonIPCsafe ( // you can use this function to pass JSBigInts
from _address _string ,
sec _keys ,
to _address _string ,
outputs ,
mix _outs ,
fake _outputs _count ,
sending _amount ,
change _amount ,
fee _amount ,
payment _id ,
unlock _time ,
rct ,
nettype
) {
unlock _time = unlock _time || 0 ;
mix _outs = mix _outs || [ ] ;
if ( rct != true ) {
return { err _msg : "Expected rct=true" }
}
if ( mix _outs . length !== outputs . length && fake _outputs _count !== 0 ) {
return { err _msg : "Wrong number of mix outs provided (" +
outputs . length +
" outputs, " +
mix _outs . length +
" mix outs)" } ;
}
for ( var i = 0 ; i < mix _outs . length ; i ++ ) {
if ( ( mix _outs [ i ] . outputs || [ ] ) . length < fake _outputs _count ) {
return { err _msg : "Not enough outputs to mix with" } ;
}
}
//
// Now we need to convert all non-JSON-serializable objects such as JSBigInts to strings etc
var sanitary _ _outputs = [ ] ;
for ( let i in outputs ) {
const sanitary _ _output =
{
amount : outputs [ i ] . amount . toString ( ) ,
public _key : outputs [ i ] . public _key ,
global _index : "" + outputs [ i ] . global _index ,
index : "" + outputs [ i ] . index ,
tx _pub _key : outputs [ i ] . tx _pub _key
} ;
if ( outputs [ i ] . rct && typeof outputs [ i ] . rct !== 'undefined' ) {
sanitary _ _output . rct = outputs [ i ] . rct ;
}
sanitary _ _outputs . push ( sanitary _ _output ) ;
}
var sanitary _ _mix _outs = [ ] ;
for ( let i in mix _outs ) {
const sanitary _ _mix _outs _and _amount =
{
amount : "" + mix _outs [ i ] . amount ,
outputs : [ ]
} ;
if ( mix _outs [ i ] . outputs && typeof mix _outs [ i ] . outputs !== 'undefined' ) {
for ( let j in mix _outs [ i ] . outputs ) {
const sanitary _ _mix _out =
{
global _index : "" + mix _outs [ i ] . outputs [ j ] . global _index ,
public _key : mix _outs [ i ] . outputs [ j ] . public _key
} ;
if ( mix _outs [ i ] . outputs [ j ] . rct && typeof mix _outs [ i ] . outputs [ j ] . rct !== 'undefined' ) {
sanitary _ _mix _out . rct = mix _outs [ i ] . outputs [ j ] . rct ;
}
sanitary _ _mix _outs _and _amount . outputs . push ( sanitary _ _mix _out ) ;
}
}
sanitary _ _mix _outs . push ( sanitary _ _mix _outs _and _amount ) ;
}
const args =
{
from _address _string : from _address _string ,
sec _viewKey _string : sec _keys . view ,
sec _spendKey _string : sec _keys . spend ,
to _address _string : to _address _string ,
sending _amount : sending _amount . toString ( ) ,
change _amount : change _amount . toString ( ) ,
fee _amount : fee _amount . toString ( ) ,
outputs : sanitary _ _outputs ,
mix _outs : sanitary _ _mix _outs ,
unlock _time : "" + unlock _time , // bridge is expecting a string
nettype _string : nettype _utils . nettype _to _API _string ( nettype )
} ;
if ( typeof payment _id !== "undefined" && payment _id ) {
args . payment _id _string = payment _id ;
}
const args _str = JSON . stringify ( args ) ;
const ret _string = this . Module . create _transaction ( args _str ) ;
const ret = JSON . parse ( ret _string ) ;
//
if ( typeof ret . err _msg !== 'undefined' && ret . err _msg ) {
return { err _msg : ret . err _msg } ;
}
return { // calling these out to set an interface
signed _serialized _tx : ret . serialized _signed _tx ,
tx _hash : ret . tx _hash ,
tx _key : ret . tx _key
} ;
}
}
//
module . exports = function ( options )
{
options = options || { }
//
return new Promise ( function ( resolve ) {
const ENVIRONMENT _IS _WEB = typeof window === "object" ;
const ENVIRONMENT _IS _WORKER = typeof importScripts === "function" ;
const ENVIRONMENT _IS _NODE = typeof process === "object" && process . browser !== true && typeof require === "function" && ENVIRONMENT _IS _WORKER == false ; // we want this to be true for Electron but not for a WebView
const ENVIRONMENT _IS _SHELL = ! ENVIRONMENT _IS _WEB && ! ENVIRONMENT _IS _NODE && ! ENVIRONMENT _IS _WORKER ;
var Module _template = { }
if ( options . asmjs != true || options . wasm == true ) { // wasm
Module _template [ "locateFile" ] = function ( filename , scriptDirectory )
{
// if (options["locateFile"]) {
// return options["locateFile"](filename, scriptDirectory)
// }
var this _scriptDirectory = scriptDirectory
const lastChar = this _scriptDirectory . charAt ( this _scriptDirectory . length - 1 )
if ( lastChar == "/" || lastChar == "\\" ) {
// ^-- this is not a '\\' on Windows because emscripten actually appends a '/'
this _scriptDirectory = this _scriptDirectory . substring ( 0 , this _scriptDirectory . length - 1 ) // remove trailing "/"
}
var fullPath = null ; // add trailing slash to this
if ( ENVIRONMENT _IS _NODE ) {
const path = require ( 'path' )
const lastPathComponent = path . basename ( this _scriptDirectory )
if ( lastPathComponent == "monero_utils" ) { // typical node or electron-main process
fullPath = path . format ( {
dir : this _scriptDirectory ,
base : filename
} )
} else {
console . warn ( "MyMoneroCoreBridge/locateFile() on node.js didn't find \"monero_utils\" (or possibly MyMoneroCoreBridge.js) itself in the expected location in the following path. The function may need to be expanded but it might in normal situations be likely to be another bug." , pathTo _cryptonoteUtilsDir )
}
} else if ( ENVIRONMENT _IS _WEB ) {
var pathTo _cryptonoteUtilsDir ;
if ( typeof _ _dirname !== undefined && _ _dirname !== "/" ) { // looks like node running in browser.. (but not going to assume it's electron-renderer since that should be taken care of by monero_utils.js itself)
// but just in case it is... here's an attempt to support it
// have to check != "/" b/c webpack (I think) replaces __dirname
pathTo _cryptonoteUtilsDir = "file://" + _ _dirname + "/" // prepending "file://" because it's going to try to stream it
} else { // actual web browser
pathTo _cryptonoteUtilsDir = this _scriptDirectory + "/mymonero_core_js/monero_utils/" // this works for the MyMonero browser build, and is quite general, at least
}
fullPath = pathTo _cryptonoteUtilsDir + filename
}
if ( fullPath == null ) {
throw "Unable to derive fullPath. Please pass locateFile() to cryptonote_utils init."
}
//
return fullPath
}
//
// NOTE: This requires src/module-post.js to be included as post-js in CMakeLists.txt under a wasm build
require ( "./MyMoneroCoreCpp" ) ( Module _template ) . ready . then ( function ( thisModule )
{
const instance = new MyMoneroCoreBridge ( thisModule ) ;
resolve ( instance ) ;
} ) . catch ( function ( e ) {
console . error ( "Error loading MyMoneroCoreCpp:" , e ) ;
reject ( e ) ;
} ) ;
} else { // this is synchronous so we can resolve immediately
resolve ( new MyMoneroCoreBridge ( require ( "./MyMoneroCoreCpp" ) ( Module _template ) ) )
}
} ) ;
} ;