// Copyright (c) 2014-2019, 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 ;
//
this . _register _async _cb _fns _ _send _funds ( ) ;
}
//
//
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 ) {
throw 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 ) {
throw 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 ) {
throw 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 ) {
throw "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 ) {
throw 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 ) {
throw 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 ) {
throw 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 ) {
throw 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 ) {
throw 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 ) {
throw 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 ) {
throw 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 ) {
throw 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 ) {
throw "Invalid tx_pub length" ;
}
if ( view _sec . length !== 64 ) {
throw "Invalid view_sec length" ;
}
if ( spend _pub . length !== 64 ) {
throw "Invalid spend_pub length" ;
}
if ( spend _sec . length !== 64 ) {
throw "Invalid spend_sec length" ;
}
if ( typeof output _index === 'undefined' || output _index === "" || output _index === null ) {
throw "Missing output_index" ;
}
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 ) {
throw 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 ) {
throw ret . err _msg ;
}
return ret . retVal ;
}
derive _public _key ( derivation , out _index , pub ) // TODO: fix legacy interface here by moving out_index to last arg pos
{
if ( typeof pub === 'undefined' || pub === "" || pub === null ) {
throw "Missing pub arg (arg pos idx 2)" ;
}
if ( typeof out _index === 'undefined' || out _index === "" || out _index === null ) {
throw "Missing out_index arg (arg pos idx 1)" ;
}
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 ) {
throw ret . err _msg ;
}
return ret . retVal ;
}
derive _subaddress _public _key (
output _key ,
derivation ,
out _index
) {
if ( typeof out _index === 'undefined' || out _index === "" || out _index === null ) {
throw "Missing out_index arg (arg pos idx 2)" ;
}
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 ) {
throw ret . err _msg ;
}
return ret . retVal ;
}
derivation _to _scalar ( derivation , output _index )
{
const args =
{
derivation : derivation ,
output _index : output _index ,
} ;
const args _str = JSON . stringify ( args ) ;
const ret _string = this . Module . derivation _to _scalar ( 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 ) {
throw "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 ) {
throw ret . err _msg
}
return { // calling these out so as to provide a stable ret val interface
amount : ret . amount , // string
mask : ret . mask ,
} ;
}
decodeRctSimple ( 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 . decodeRctSimple ( 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 ) {
throw ret . err _msg ; // TODO: maybe return this somehow
}
return ret . retVal ; // this is a string - pass it to new JSBigInt(…)
}
estimate _rct _tx _size ( n _inputs , mixin , n _outputs , extra _size , bulletproof )
{
const args =
{
n _inputs ,
mixin ,
n _outputs ,
extra _size ,
bulletproof
} ;
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 }
}
return parseInt ( ret . retVal , 10 ) ;
}
//
// Send
_ _key _for _fromCpp _ _send _funds _ _get _unspent _outs ( task _id )
{
return ` fromCpp__send_funds__get_unspent_outs- ${ task _id } `
}
_ _key _for _fromCpp _ _send _funds _ _get _random _outs ( task _id )
{
return ` fromCpp__send_funds__get_random_outs- ${ task _id } `
}
_ _key _for _fromCpp _ _send _funds _ _submit _raw _tx ( task _id )
{
return ` fromCpp__send_funds__submit_raw_tx- ${ task _id } `
}
_ _key _for _fromCpp _ _send _funds _ _status _update ( task _id )
{
return ` fromCpp__send_funds__status_update- ${ task _id } `
}
_ _key _for _fromCpp _ _send _funds _ _error ( task _id )
{
return ` fromCpp__send_funds__error- ${ task _id } `
}
_ _key _for _fromCpp _ _send _funds _ _success ( task _id )
{
return ` fromCpp__send_funds__success- ${ task _id } `
}
_ _new _cb _args _with ( task _id , err _msg , res )
{
const args =
{
task _id : task _id
} ;
if ( typeof err _msg !== 'undefined' && err _msg ) {
args . err _msg = err _msg ; // errors must be sent back so that C++ can free heap vals container
} else {
args . res = res ;
}
return args ;
}
_register _async _cb _fns _ _send _funds ( )
{
const self = this
self . Module . fromCpp _ _send _funds _ _get _unspent _outs = function ( task _id , req _params )
{
self . _cb _handlers _ _send _funds [ self . _ _key _for _fromCpp _ _send _funds _ _get _unspent _outs ( task _id ) ] ( req _params ) ;
} ;
self . Module . fromCpp _ _send _funds _ _get _random _outs = function ( task _id , req _params )
{
self . _cb _handlers _ _send _funds [ self . _ _key _for _fromCpp _ _send _funds _ _get _random _outs ( task _id ) ] ( req _params ) ;
} ;
self . Module . fromCpp _ _send _funds _ _submit _raw _tx = function ( task _id , req _params )
{
self . _cb _handlers _ _send _funds [ self . _ _key _for _fromCpp _ _send _funds _ _submit _raw _tx ( task _id ) ] ( req _params ) ;
} ;
self . Module . fromCpp _ _send _funds _ _status _update = function ( task _id , params )
{
self . _cb _handlers _ _send _funds [ self . _ _key _for _fromCpp _ _send _funds _ _status _update ( task _id ) ] ( params ) ;
} ;
self . Module . fromCpp _ _send _funds _ _error = function ( task _id , params )
{
self . _cb _handlers _ _send _funds [ self . _ _key _for _fromCpp _ _send _funds _ _error ( task _id ) ] ( params ) ;
} ;
self . Module . fromCpp _ _send _funds _ _success = function ( task _id , params )
{
self . _cb _handlers _ _send _funds [ self . _ _key _for _fromCpp _ _send _funds _ _success ( task _id ) ] ( params ) ;
} ;
}
_ _new _task _id ( )
{
return Math . random ( ) . toString ( 36 ) . substr ( 2 , 9 ) ; // doesn't have to be super random
}
async _ _send _funds ( fn _args )
{
const self = this ;
const task _id = self . _ _new _task _id ( ) ;
// register cb handler fns to wait for calls with thi task id
if ( typeof self . _cb _handlers _ _send _funds == 'undefined' || ! self . _cb _handlers _ _send _funds ) {
self . _cb _handlers _ _send _funds = { }
}
self . _cb _handlers _ _send _funds [ self . _ _key _for _fromCpp _ _send _funds _ _get _unspent _outs ( task _id ) ] = function ( req _params )
{
// convert bridge-strings to native primitive types
req _params . use _dust = ret _val _boolstring _to _bool ( req _params . use _dust )
req _params . mixin = parseInt ( req _params . mixin )
//
fn _args . get _unspent _outs _fn ( req _params , function ( err _msg , res )
{
const args = self . _ _new _cb _args _with ( task _id , err _msg , res ) ;
self . Module . send _cb _I _ _got _unspent _outs ( JSON . stringify ( args ) )
} ) ;
} ;
self . _cb _handlers _ _send _funds [ self . _ _key _for _fromCpp _ _send _funds _ _get _random _outs ( task _id ) ] = function ( req _params )
{
// convert bridge-strings to native primitive types
req _params . count = parseInt ( req _params . count )
//
fn _args . get _random _outs _fn ( req _params , function ( err _msg , res )
{
const args = self . _ _new _cb _args _with ( task _id , err _msg , res ) ;
self . Module . send _cb _II _ _got _random _outs ( JSON . stringify ( args ) )
} ) ;
} ;
self . _cb _handlers _ _send _funds [ self . _ _key _for _fromCpp _ _send _funds _ _submit _raw _tx ( task _id ) ] = function ( req _params )
{
fn _args . submit _raw _tx _fn ( req _params , function ( err _msg , res )
{
const args = self . _ _new _cb _args _with ( task _id , err _msg , res ) ;
self . Module . send _cb _III _ _submitted _tx ( JSON . stringify ( args ) )
} )
} ;
self . _cb _handlers _ _send _funds [ self . _ _key _for _fromCpp _ _send _funds _ _status _update ( task _id ) ] = function ( params )
{
params . code = parseInt ( params . code )
//
fn _args . status _update _fn ( params ) ;
} ;
self . _cb _handlers _ _send _funds [ self . _ _key _for _fromCpp _ _send _funds _ _error ( task _id ) ] = function ( params )
{
fn _args . error _fn ( params ) ;
} ;
self . _cb _handlers _ _send _funds [ self . _ _key _for _fromCpp _ _send _funds _ _success ( task _id ) ] = function ( params )
{
params . mixin = parseInt ( params . mixin )
//
fn _args . success _fn ( params ) ;
} ;
const args =
{
task _id : task _id ,
is _sweeping : fn _args . is _sweeping ,
sending _amount : "" + fn _args . sending _amount ,
from _address _string : fn _args . from _address _string ,
sec _viewKey _string : fn _args . sec _viewKey _string ,
sec _spendKey _string : fn _args . sec _spendKey _string ,
pub _spendKey _string : fn _args . pub _spendKey _string ,
to _address _string : fn _args . to _address _string ,
priority : "" + fn _args . priority ,
nettype _string : nettype _utils . nettype _to _API _string ( fn _args . nettype )
} ;
if ( typeof fn _args . payment _id _string !== 'undefined' && fn _args . payment _id _string ) {
args . payment _id _string = fn _args . payment _id _string ;
}
if ( typeof fn _args . unlock _time !== 'undefined' && fn _args . unlock _time !== null ) {
args . unlock _time = "" + fn _args . unlock _time ; // bridge is expecting a string
}
const args _str = JSON . stringify ( args , null , '' )
this . Module . send _funds ( args _str ) ;
}
}
//
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 ;
//
if ( ( typeof options . asmjs === 'undefined' || options . asmjs === null ) && ( typeof options . wasm === 'undefined' || options . wasm === null ) ) {
var use _asmjs = false ;
if ( ENVIRONMENT _IS _WEB ) {
var hasWebAssembly = false
try {
if ( typeof WebAssembly === "object" && typeof WebAssembly . instantiate === "function" ) {
const module = new WebAssembly . Module ( Uint8Array . of ( 0x0 , 0x61 , 0x73 , 0x6d , 0x01 , 0x00 , 0x00 , 0x00 ) ) ;
if ( module instanceof WebAssembly . Module ) {
var isInstance = new WebAssembly . Instance ( module ) instanceof WebAssembly . Instance ;
if ( isInstance ) {
// TODO: add ios 11 mobile safari bug check to hasWebAssembly
}
// until then…
hasWebAssembly = isInstance
}
}
} catch ( e ) {
// avoiding empty block statement warning..
hasWebAssembly = false // to be clear
}
use _asmjs = hasWebAssembly != true
}
options . asmjs = use _asmjs ;
}
//
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 , reject ) {
var Module _template = { }
if ( options . asmjs != true || options . wasm == true ) { // wasm
console . log ( "Using wasm: " , true )
//
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
console . log ( "Using wasm: " , false )
//
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 - and the github/fetch polyfill does not appear to actually support mode (for 'same-origin' policy) anyway - probably not worth it yet
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 ) // I do not believe this is a safety concern, because content is server-controlled; https://humanwhocodes.com/blog/2013/06/25/eval-isnt-evil-just-misunderstood/
} 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 )
}
} ) ;
} ;