// 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 monero _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
}
function bridge _sanitized _ _spendable _out ( raw _ _out )
{
const sanitary _ _output =
{
amount : raw _ _out . amount . toString ( ) ,
public _key : raw _ _out . public _key ,
global _index : "" + raw _ _out . global _index ,
index : "" + raw _ _out . index ,
tx _pub _key : raw _ _out . tx _pub _key
} ;
if ( raw _ _out . rct && typeof raw _ _out . rct !== 'undefined' ) {
sanitary _ _output . rct = raw _ _out . rct ;
}
return sanitary _ _output ;
}
//
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 ,
} ;
}
estimated _tx _network _fee ( fee _per _kb _ _string , priority , optl _ _fee _per _b _string ) // this is until we switch the server over to fee per b
{ // TODO update this API to take object rather than arg list
const args =
{
fee _per _b : typeof optl _ _fee _per _b _string !== undefined && optl _ _fee _per _b _string != null
? optl _ _fee _per _b _string
: ( new JSBigInt ( fee _per _kb _ _string ) ) . divide ( 1024 ) . toString ( ) /*kib -> b*/ ,
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(…)
}
send _step1 _ _prepare _params _for _get _decoys (
is _sweeping ,
sending _amount , // this may be 0 if sweeping
fee _per _b ,
priority ,
unspent _outputs ,
optl _ _payment _id _string , // this may be nil
optl _ _passedIn _attemptAt _fee
) {
var sanitary _ _unspent _outputs = [ ] ;
for ( let i in unspent _outputs ) {
const sanitary _ _output = bridge _sanitized _ _spendable _out ( unspent _outputs [ i ] )
sanitary _ _unspent _outputs . push ( sanitary _ _output ) ;
}
const args =
{
sending _amount : sending _amount . toString ( ) ,
is _sweeping : "" + is _sweeping , // bool -> string
priority : "" + priority ,
fee _per _b : fee _per _b . toString ( ) ,
unspent _outs : sanitary _ _unspent _outputs // outs, not outputs
} ;
if ( typeof optl _ _payment _id _string !== "undefined" && optl _ _payment _id _string && optl _ _payment _id _string != "" ) {
args . payment _id _string = optl _ _payment _id _string ;
}
if ( typeof optl _ _passedIn _attemptAt _fee !== "undefined" && optl _ _passedIn _attemptAt _fee && optl _ _passedIn _attemptAt _fee != "" ) {
args . passedIn _attemptAt _fee = optl _ _passedIn _attemptAt _fee . toString ( ) ; // ought to be a string but in case it's a JSBigInt…
}
const args _str = JSON . stringify ( args ) ;
const ret _string = this . Module . send _step1 _ _prepare _params _for _get _decoys ( args _str ) ;
const ret = JSON . parse ( ret _string ) ;
// special case: err_code of needMoreMoneyThanFound; rewrite err_msg
if ( ret . err _code == "90" || ret . err _code == 90 ) { // declared in mymonero-core-cpp/src/monero_transfer_utils.hpp
return {
required _balance : ret . required _balance ,
spendable _balance : ret . spendable _balance ,
err _msg : ` Spendable balance too low. Have ${
monero _amount _format _utils . formatMoney ( new JSBigInt ( ret . spendable _balance ) )
} $ { monero _config . coinSymbol } ; need $ {
monero _amount _format _utils . formatMoney ( new JSBigInt ( ret . required _balance ) )
} $ { monero _config . coinSymbol } . `
} ;
}
if ( typeof ret . err _msg !== 'undefined' && ret . err _msg ) {
return { err _msg : ret . err _msg } ;
}
return { // calling these out to set an interface
mixin : parseInt ( ret . mixin ) , // for the server API request to RandomOuts
using _fee : ret . using _fee , // string; can be passed to step2
change _amount : ret . change _amount , // string for step2
using _outs : ret . using _outs , // this can be passed straight to step2
final _total _wo _fee : ret . final _total _wo _fee // aka sending_amount for step2
} ;
}
send _step2 _ _try _create _transaction ( // send only IPC-safe vals - no JSBigInts
from _address _string ,
sec _keys ,
to _address _string ,
using _outs ,
mix _outs ,
fake _outputs _count ,
final _total _wo _fee ,
change _amount ,
fee _amount ,
payment _id ,
priority ,
fee _per _b , // not kib - if fee_per_kb, /= 1024
unlock _time ,
nettype
) {
unlock _time = unlock _time || 0 ;
mix _outs = mix _outs || [ ] ;
// NOTE: we also do this check in the C++... may as well remove it from here
if ( mix _outs . length !== using _outs . length && fake _outputs _count !== 0 ) {
return {
err _msg : "Wrong number of mix outs provided (" +
using _outs . length + " using_outs, " +
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 - not that there should be any!
// - and all numbers to strings - especially those which may be uint64_t on the receiving side
var sanitary _ _using _outs = [ ] ;
for ( let i in using _outs ) {
const sanitary _ _output = bridge _sanitized _ _spendable _out ( using _outs [ i ] )
sanitary _ _using _outs . push ( sanitary _ _output ) ;
}
var sanitary _ _mix _outs = [ ] ;
for ( let i in mix _outs ) {
const sanitary _ _mix _outs _and _amount =
{
amount : mix _outs [ i ] . amount . toString ( ) , // it should be a string, but in case it's not
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 , // number to string
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 ,
final _total _wo _fee : final _total _wo _fee . toString ( ) ,
change _amount : change _amount . toString ( ) ,
fee _amount : fee _amount . toString ( ) ,
priority : "" + priority ,
fee _per _b : fee _per _b . toString ( ) ,
using _outs : sanitary _ _using _outs ,
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 . send _step2 _ _try _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 , tx _must _be _reconstructed : false } ;
}
if ( ret . tx _must _be _reconstructed == "true" || ret . tx _must _be _reconstructed == true ) {
if ( typeof ret . fee _actually _needed == 'undefined' || ! ret . fee _actually _needed ) {
throw "tx_must_be_reconstructed; expected non-nil fee_actually_needed"
}
return {
tx _must _be _reconstructed : ret . tx _must _be _reconstructed , // if true, re-do procedure from step1 except for requesting UnspentOuts (that can be done oncet)
fee _actually _needed : ret . fee _actually _needed // can be passed back to step1
}
}
return { // calling these out to set an interface
tx _must _be _reconstructed : false , // in case caller is not checking for nil
signed _serialized _tx : ret . serialized _signed _tx , // this name change should be fixed to serialized_signed_tx
tx _hash : ret . tx _hash ,
tx _key : ret . tx _key
} ;
}
}
//
module . exports = function ( options )
{
options = options || { }
//
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 ;
function locateFile ( 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
}
return new Promise ( function ( resolve ) {
var Module _template = { }
if ( options . asmjs != true || options . wasm == true ) { // wasm
Module _template [ "locateFile" ] = locateFile
//
// NOTE: This requires src/module-post.js to be included as post-js in CMakeLists.txt under a wasm build
require ( "./MyMoneroCoreCpp_WASM" ) ( Module _template ) . ready . then ( function ( thisModule )
{
const instance = new MyMoneroCoreBridge ( thisModule ) ;
resolve ( instance ) ;
} ) . catch ( function ( e ) {
console . error ( "Error loading MyMoneroCoreCpp_WASM:" , e ) ;
reject ( e ) ;
} ) ;
} else { // this is synchronous so we can resolve immediately
var scriptDirectory = "" ; // this was extracted from emscripten - it could get factored if anything else would ever need it
if ( ENVIRONMENT _IS _NODE ) {
scriptDirectory = _ _dirname + "/" ;
} else if ( ENVIRONMENT _IS _WEB || ENVIRONMENT _IS _WORKER ) {
if ( ENVIRONMENT _IS _WORKER ) {
scriptDirectory = self . location . href
} else if ( document . currentScript ) {
scriptDirectory = document . currentScript . src
}
var _scriptDir = typeof document !== 'undefined' && document . currentScript ? document . currentScript . src : undefined ;
if ( _scriptDir ) {
scriptDirectory = _scriptDir
}
if ( scriptDirectory . indexOf ( "blob:" ) !== 0 ) {
scriptDirectory = scriptDirectory . substr ( 0 , scriptDirectory . lastIndexOf ( "/" ) + 1 )
} else {
scriptDirectory = ""
}
}
var read _fn ;
if ( ENVIRONMENT _IS _NODE ) {
read _fn = function ( filepath )
{
return require ( "fs" ) . readFileSync ( require ( "path" ) . normalize ( filepath ) ) . toString ( )
} ;
} else if ( ENVIRONMENT _IS _WEB || ENVIRONMENT _IS _WORKER ) {
read _fn = function ( url )
{ // it's an option to move this over to fetch, but, fetch requires a polyfill for these older browsers anyway - making fetch an automatic dep just for asmjs fallback - probably not worth it yet - but it would be if fetch were to become a dep for another reason, such as a networked SendFunds() implementation
var xhr = new XMLHttpRequest ( )
xhr . open ( "GET" , url , false )
xhr . send ( null )
//
return xhr . responseText
} ;
} else {
throw "Unsupported environment - please implement file reading for asmjs fallback case"
}
const filepath = locateFile ( 'MyMoneroCoreCpp_ASMJS.asm.js' , scriptDirectory )
const content = read _fn ( filepath )
// TODO: verify content - for now, relying on same-origin and tls/ssl
var Module = { }
try {
eval ( content ) // emscripten also does an eval
} catch ( e ) {
reject ( e )
return
}
setTimeout ( function ( )
{ // "delaying even 1ms is enough to allow compilation memory to be reclaimed"
Module _template [ 'asm' ] = Module [ 'asm' ]
Module = null
resolve ( new MyMoneroCoreBridge ( require ( "./MyMoneroCoreCpp_ASMJS" ) ( Module _template ) ) )
} , 1 )
}
} ) ;
} ;