@ -47,11 +47,15 @@ var cnUtil = (function(initConfig) {
var ENCRYPTED _PAYMENT _ID _TAIL = 141 ;
var CRYPTONOTE _PUBLIC _ADDRESS _BASE58 _PREFIX = config . addressPrefix ;
var CRYPTONOTE _PUBLIC _INTEGRATED _ADDRESS _BASE58 _PREFIX = config . integratedAddressPrefix ;
var CRYPTONOTE _PUBLIC _SUBADDRESS _BASE58 _PREFIX = config . subAddressPrefix ;
if ( config . testnet === true )
{
CRYPTONOTE _PUBLIC _ADDRESS _BASE58 _PREFIX = config . addressPrefixTestnet ;
CRYPTONOTE _PUBLIC _INTEGRATED _ADDRESS _BASE58 _PREFIX = config . integratedAddressPrefixTestnet ;
CRYPTONOTE _PUBLIC _SUBADDRESS _BASE58 _PREFIX = config . subAddressPrefixTestnet ;
}
var UINT64 _MAX = new JSBigInt ( 2 ) . pow ( 64 ) ;
var CURRENT _TX _VERSION = 2 ;
var OLD _TX _VERSION = 1 ;
@ -507,13 +511,21 @@ var cnUtil = (function(initConfig) {
var prefix = this . encode _varint ( CRYPTONOTE _PUBLIC _ADDRESS _BASE58 _PREFIX ) ;
return cnBase58 . encode ( prefix + spend . pub ) . slice ( 0 , 44 ) ;
} ;
this . is _subaddress = function ( address ) {
var dec = cnBase58 . decode ( address ) ;
var expectedPrefixSub = this . encode _varint ( CRYPTONOTE _PUBLIC _SUBADDRESS _BASE58 _PREFIX ) ;
var prefix = dec . slice ( 0 , expectedPrefixSub . length ) ;
return ( prefix === expectedPrefixSub ) ;
}
this . decode _address = function ( address ) {
var dec = cnBase58 . decode ( address ) ;
var expectedPrefix = this . encode _varint ( CRYPTONOTE _PUBLIC _ADDRESS _BASE58 _PREFIX ) ;
var expectedPrefixInt = this . encode _varint ( CRYPTONOTE _PUBLIC _INTEGRATED _ADDRESS _BASE58 _PREFIX ) ;
var expectedPrefixSub = this . encode _varint ( CRYPTONOTE _PUBLIC _SUBADDRESS _BASE58 _PREFIX ) ;
var prefix = dec . slice ( 0 , expectedPrefix . length ) ;
if ( prefix !== expectedPrefix && prefix !== expectedPrefixInt ) {
if ( prefix !== expectedPrefix && prefix !== expectedPrefixInt && prefix !== expectedPrefixSub ) {
throw "Invalid address prefix" ;
}
dec = dec . slice ( expectedPrefix . length ) ;
@ -523,7 +535,11 @@ var cnUtil = (function(initConfig) {
var intPaymentId = dec . slice ( 128 , 128 + ( INTEGRATED _ID _SIZE * 2 ) ) ;
var checksum = dec . slice ( 128 + ( INTEGRATED _ID _SIZE * 2 ) , 128 + ( INTEGRATED _ID _SIZE * 2 ) + ( ADDRESS _CHECKSUM _SIZE * 2 ) ) ;
var expectedChecksum = this . cn _fast _hash ( prefix + spend + view + intPaymentId ) . slice ( 0 , ADDRESS _CHECKSUM _SIZE * 2 ) ;
} else if ( prefix === expectedPrefix ) {
var checksum = dec . slice ( 128 , 128 + ( ADDRESS _CHECKSUM _SIZE * 2 ) ) ;
var expectedChecksum = this . cn _fast _hash ( prefix + spend + view ) . slice ( 0 , ADDRESS _CHECKSUM _SIZE * 2 ) ;
} else {
// if its not regular address, nor integrated, than it must be subaddress
var checksum = dec . slice ( 128 , 128 + ( ADDRESS _CHECKSUM _SIZE * 2 ) ) ;
var expectedChecksum = this . cn _fast _hash ( prefix + spend + view ) . slice ( 0 , ADDRESS _CHECKSUM _SIZE * 2 ) ;
}
@ -1629,7 +1645,7 @@ var cnUtil = (function(initConfig) {
return sigs ;
} ;
this . construct _tx = function ( keys , sources , dsts , fee _amount , payment _id , pid _encrypt , realDestViewKey , unlock _time , rct ) {
this . construct _tx = function ( keys , sources , dsts , fee _amount , payment _id , pid _encrypt , realDestViewKey , unlock _time , rct , changeAddress ) {
//we move payment ID stuff here, because we need txkey to encrypt
var txkey = this . random _keypair ( ) ;
console . log ( txkey ) ;
@ -1648,6 +1664,12 @@ var cnUtil = (function(initConfig) {
console . log ( "Extra nonce: " + nonce ) ;
extra = this . add _nonce _to _extra ( extra , nonce ) ;
}
// for sending to a subaddress, need to generate new tx public key
//var sub_addr_decoded = this.decode_address(dsts[0].address); // for example dest[0] is subaddress
//txkey.pub = ge_scalarmult(sub_addr_decoded.spend, txkey.sec);
var tx = {
unlock _time : unlock _time ,
version : rct ? CURRENT _TX _VERSION : OLD _TX _VERSION ,
@ -1661,7 +1683,8 @@ var cnUtil = (function(initConfig) {
} else {
tx . signatures = [ ] ;
}
tx . extra = this . add _pub _key _to _extra ( tx . extra , txkey . pub ) ;
//tx.extra = this.add_pub_key_to_extra(tx.extra, txkey.pub);
tx . prvkey = txkey . sec ;
var in _contexts = [ ] ;
@ -1712,12 +1735,33 @@ var cnUtil = (function(initConfig) {
var outputs _money = JSBigInt . ZERO ;
var out _index = 0 ;
var amountKeys = [ ] ; //rct only
// keep generated tx public key, just in case when sending to a subaddress.
// when sending to a subaddress, new txkey.pub is generated, but txkey.sec stays same
var orginal _tx _pub _key = txkey . pub ;
for ( i = 0 ; i < dsts . length ; ++ i ) {
if ( new JSBigInt ( dsts [ i ] . amount ) . compare ( 0 ) < 0 ) {
throw "dst.amount < 0" ; //amount can be zero if no change
}
dsts [ i ] . keys = this . decode _address ( dsts [ i ] . address ) ;
var out _derivation = this . generate _key _derivation ( dsts [ i ] . keys . view , txkey . sec ) ;
if ( this . is _subaddress ( dsts [ i ] . address ) )
{
txkey . pub = ge _scalarmult ( dsts [ i ] . keys . spend , txkey . sec ) ;
}
var out _derivation ;
if ( dsts [ i ] . address === changeAddress . address )
{
out _derivation = this . generate _key _derivation ( txkey . pub , changeAddress . view _key ) ;
}
else
{
out _derivation = this . generate _key _derivation ( dsts [ i ] . keys . view , txkey . sec ) ;
}
if ( rct ) {
amountKeys . push ( this . derivation _to _scalar ( out _derivation , out _index ) ) ;
}
@ -1734,9 +1778,14 @@ var cnUtil = (function(initConfig) {
++ out _index ;
outputs _money = outputs _money . add ( dsts [ i ] . amount ) ;
}
tx . extra = this . add _pub _key _to _extra ( tx . extra , txkey . pub ) ;
if ( outputs _money . add ( fee _amount ) . compare ( inputs _money ) > 0 ) {
throw "outputs money (" + this . formatMoneyFull ( outputs _money ) + ") + fee (" + this . formatMoneyFull ( fee _amount ) + ") > inputs money (" + this . formatMoneyFull ( inputs _money ) + ")" ;
}
if ( ! rct ) {
for ( i = 0 ; i < sources . length ; ++ i ) {
var src _keys = [ ] ;
@ -1795,7 +1844,7 @@ var cnUtil = (function(initConfig) {
console . log ( tx ) ;
return tx ;
} ;
this . create _transaction = function ( pub _keys , sec _keys , dsts , outputs , mix _outs , fake _outputs _count , fee _amount , payment _id , pid _encrypt , realDestViewKey , unlock _time , rct ) {
this . create _transaction = function ( pub _keys , sec _keys , dsts , outputs , mix _outs , fake _outputs _count , fee _amount , payment _id , pid _encrypt , realDestViewKey , unlock _time , rct , changeAddress ) {
unlock _time = unlock _time || 0 ;
mix _outs = mix _outs || [ ] ;
var i , j ;
@ -1915,7 +1964,7 @@ var cnUtil = (function(initConfig) {
} else if ( cmp > 0 ) {
throw "Need more money than found! (have: " + cnUtil . formatMoney ( found _money ) + " need: " + cnUtil . formatMoney ( needed _money ) + ")" ;
}
return this . construct _tx ( keys , sources , dsts , fee _amount , payment _id , pid _encrypt , realDestViewKey , unlock _time , rct );
return this . construct _tx ( keys , sources , dsts , fee _amount , payment _id , pid _encrypt , realDestViewKey , unlock _time , rct , changeAddress );
} ;
this . estimateRctSize = function ( inputs , mixin , outputs ) {