const bs58check = require ( 'bs58check' ) ;
const bitcoin = require ( 'bitcoinjs-lib' ) ;
module . exports = ( shepherd ) => {
shepherd . elections = { } ;
shepherd . hex2str = ( hexx ) => {
const hex = hexx . toString ( ) ; // force conversion
let str = '' ;
for ( let i = 0 ; i < hex . length ; i += 2 ) {
str += String . fromCharCode ( parseInt ( hex . substr ( i , 2 ) , 16 ) ) ;
}
return str ;
} ;
shepherd . post ( '/elections/status' , ( req , res , next ) => {
if ( shepherd . checkToken ( req . body . token ) ) {
const successObj = {
msg : 'success' ,
result : shepherd . elections . pub ? shepherd . elections . pub : 'unauth' ,
} ;
res . end ( JSON . stringify ( successObj ) ) ;
} else {
const errorObj = {
msg : 'error' ,
result : 'unauthorized access' ,
} ;
res . end ( JSON . stringify ( errorObj ) ) ;
}
} ) ;
shepherd . post ( '/elections/login' , ( req , res , next ) => {
if ( shepherd . checkToken ( req . body . token ) ) {
const _ seed = req . body . seed ;
const _ network = req . body . network ;
let keys ;
let isWif = false ;
if ( _ seed . match ( '^[a-zA-Z0-9]{34}$' ) ) {
shepherd . log ( 'watchonly elections pub addr' ) ;
shepherd . elections = {
priv : _ seed ,
pub : _ seed ,
} ;
} else {
try {
bs58check . decode ( _ seed ) ;
isWif = true ;
} catch ( e ) { }
if ( isWif ) {
try {
let key = bitcoin . ECPair . fromWIF ( _ seed , shepherd . getNetworkData ( _ network . toLowerCase ( ) ) , true ) ;
keys = {
priv : key . toWIF ( ) ,
pub : key . getAddress ( ) ,
} ;
} catch ( e ) {
_ wifError = true ;
}
} else {
keys = shepherd . seedToWif ( _ seed , _ network , req . body . iguana ) ;
}
shepherd . elections = {
priv : keys . priv ,
pub : keys . pub ,
} ;
}
const successObj = {
msg : 'success' ,
result : shepherd . elections . pub ,
} ;
res . end ( JSON . stringify ( successObj ) ) ;
} else {
const errorObj = {
msg : 'error' ,
result : 'unauthorized access' ,
} ;
res . end ( JSON . stringify ( errorObj ) ) ;
}
} ) ;
shepherd . post ( '/elections/logout' , ( req , res , next ) => {
if ( shepherd . checkToken ( req . body . token ) ) {
shepherd . elections = { } ;
const successObj = {
msg : 'success' ,
result : true ,
} ;
res . end ( JSON . stringify ( successObj ) ) ;
} else {
const errorObj = {
msg : 'error' ,
result : 'unauthorized access' ,
} ;
res . end ( JSON . stringify ( errorObj ) ) ;
}
} ) ;
shepherd . electionsDecodeTx = ( decodedTx , ecl , network , _ network , transaction , blockInfo , address ) => {
let txInputs = [ ] ;
return new shepherd . Promise ( ( resolve , reject ) => {
if ( decodedTx &&
decodedTx . inputs ) {
shepherd . Promise . all ( decodedTx . inputs . map ( ( _ decodedInput , index ) => {
return new shepherd . Promise ( ( _ resolve , _ reject ) => {
if ( _ decodedInput . txid !== '0000000000000000000000000000000000000000000000000000000000000000' ) {
ecl . blockchainTransactionGet ( _ decodedInput . txid )
. then ( ( rawInput ) => {
const decodedVinVout = shepherd . electrumJSTxDecoder ( rawInput , network , _ network ) ;
shepherd . log ( 'electrum raw input tx ==>' , true ) ;
if ( decodedVinVout ) {
shepherd . log ( decodedVinVout . outputs [ _ decodedInput . n ] , true ) ;
txInputs . push ( decodedVinVout . outputs [ _ decodedInput . n ] ) ;
_ resolve ( true ) ;
} else {
_ resolve ( true ) ;
}
} ) ;
} else {
_ resolve ( true ) ;
}
} ) ;
} ) )
. then ( promiseResult => {
const _ parsedTx = {
network : decodedTx . network ,
format : decodedTx . format ,
inputs : txInputs ,
outputs : decodedTx . outputs ,
height : transaction . height ,
timestamp : Number ( transaction . height ) === 0 ? Math . floor ( Date . now ( ) / 1000 ) : blockInfo . timestamp ,
} ;
resolve ( shepherd . parseTransactionAddresses ( _ parsedTx , address , network , true ) ) ;
} ) ;
} else {
const _ parsedTx = {
network : decodedTx . network ,
format : 'cant parse' ,
inputs : 'cant parse' ,
outputs : 'cant parse' ,
height : transaction . height ,
timestamp : Number ( transaction . height ) === 0 ? Math . floor ( Date . now ( ) / 1000 ) : blockInfo . timestamp ,
} ;
resolve ( shepherd . parseTransactionAddresses ( _ parsedTx , address , network ) ) ;
}
} ) ;
} ;
shepherd . get ( '/elections/listtransactions' , ( req , res , next ) => {
if ( shepherd . checkToken ( req . query . token ) ) {
const network = req . query . network || shepherd . findNetworkObj ( req . query . coin ) ;
const ecl = new shepherd . electrumJSCore ( shepherd . electrumServers [ network ] . port , shepherd . electrumServers [ network ] . address , shepherd . electrumServers [ network ] . proto ) ; // tcp or tls
const type = req . query . type ;
const _ address = req . query . address ;
shepherd . log ( 'electrum elections listtransactions ==>' , true ) ;
const MAX_TX = req . query . maxlength || 10 ;
ecl . connect ( ) ;
ecl . blockchainAddressGetHistory ( _ address )
. then ( ( json ) => {
if ( json &&
json . length ) {
let _ rawtx = [ ] ;
json = shepherd . sortTransactions ( json ) ;
// json = json.length > MAX_TX ? json.slice(0, MAX_TX) : json;
shepherd . log ( json . length , true ) ;
shepherd . Promise . all ( json . map ( ( transaction , index ) => {
return new shepherd . Promise ( ( resolve , reject ) => {
ecl . blockchainBlockGetHeader ( transaction . height )
. then ( ( blockInfo ) => {
if ( blockInfo &&
blockInfo . timestamp ) {
ecl . blockchainTransactionGet ( transaction [ 'tx_hash' ] )
. then ( ( _ rawtxJSON ) => {
//shepherd.log('electrum gettransaction ==>', true);
//shepherd.log((index + ' | ' + (_rawtxJSON.length - 1)), true);
//shepherd.log(_rawtxJSON, true);
// decode tx
const _ network = shepherd . getNetworkData ( network ) ;
const decodedTx = shepherd . electrumJSTxDecoder ( _ rawtxJSON , network , _ network ) ;
let _ res = { } ;
let _ opreturnFound = false ;
let _ region ;
if ( decodedTx &&
decodedTx . outputs &&
decodedTx . outputs . length ) {
for ( let i = 0 ; i < decodedTx . outputs . length ; i ++ ) {
if ( decodedTx . outputs [ i ] . scriptPubKey . asm . indexOf ( 'OP_RETURN' ) > - 1 ) {
_ opreturnFound = true ;
_ region = shepherd . hex2str ( decodedTx . outputs [ i ] . scriptPubKey . hex . substr ( 4 , decodedTx . outputs [ i ] . scriptPubKey . hex . length ) ) ;
shepherd . log ( ` found opreturn tag ${ _ region } ` ) ;
break ;
}
}
}
if ( _ opreturnFound ) {
let _ candidate = { } ;
for ( let i = 0 ; i < decodedTx . outputs . length ; i ++ ) {
if ( type === 'voter' &&
decodedTx . outputs [ i ] . scriptPubKey . addresses &&
decodedTx . outputs [ i ] . scriptPubKey . addresses [ 0 ] &&
decodedTx . outputs [ i ] . scriptPubKey . addresses [ 0 ] !== _ address ) {
if ( _ region === 'ne2k18-na-1-eu-2-ae-3-sh-4' ) {
const _ regionsLookup = [
'ne2k18-na' ,
'ne2k18-eu' ,
'ne2k18-ae' ,
'ne2k18-sh'
] ;
shepherd . log ( ` i voted ${ decodedTx . outputs [ i ] . value } for ${ decodedTx . outputs [ i ] . scriptPubKey . addresses [ 0 ] } ` ) ;
_ rawtx . push ( {
address : decodedTx . outputs [ i ] . scriptPubKey . addresses [ 0 ] ,
amount : decodedTx . outputs [ i ] . value ,
region : _ regionsLookup [ i ] ,
timestamp : blockInfo . timestamp ,
} ) ;
resolve ( true ) ;
} else {
shepherd . log ( ` i voted ${ decodedTx . outputs [ i ] . value } for ${ decodedTx . outputs [ i ] . scriptPubKey . addresses [ 0 ] } ` ) ;
_ rawtx . push ( {
address : decodedTx . outputs [ i ] . scriptPubKey . addresses [ 0 ] ,
amount : decodedTx . outputs [ i ] . value ,
region : _ region ,
timestamp : blockInfo . timestamp ,
} ) ;
resolve ( true ) ;
}
}
if ( type === 'candidate' ) {
if ( _ region === 'ne2k18-na-1-eu-2-ae-3-sh-4' ) {
if ( decodedTx . outputs [ i ] . scriptPubKey . addresses [ 0 ] === _ address && decodedTx . outputs [ i ] . scriptPubKey . asm . indexOf ( 'OP_RETURN' ) === - 1 ) {
const _ regionsLookup = [
'ne2k18-na' ,
'ne2k18-eu' ,
'ne2k18-ae' ,
'ne2k18-sh'
] ;
shepherd . electionsDecodeTx ( decodedTx , ecl , network , _ network , transaction , blockInfo , _ address )
. then ( ( res ) => {
shepherd . log ( ` i received ${ decodedTx . outputs [ i ] . value } from ${ res . outputAddresses [ 0 ] } out ${ i } region ${ _ regionsLookup [ i ] } ` ) ;
_ rawtx . push ( {
address : res . outputAddresses [ 0 ] ,
timestamp : blockInfo . timestamp ,
amount : decodedTx . outputs [ i ] . value ,
region : _ regionsLookup [ i ] ,
} ) ;
resolve ( true ) ;
} ) ;
}
} else {
shepherd . electionsDecodeTx ( decodedTx , ecl , network , _ network , transaction , blockInfo , _ address )
. then ( ( res ) => {
if ( decodedTx . outputs [ i ] . scriptPubKey . addresses [ 0 ] === _ address ) {
_ candidate . amount = decodedTx . outputs [ i ] . value ;
} else if ( decodedTx . outputs [ i ] . scriptPubKey . addresses [ 0 ] !== _ address && decodedTx . outputs [ i ] . scriptPubKey . asm . indexOf ( 'OP_RETURN' ) === - 1 ) {
_ candidate . address = decodedTx . outputs [ i ] . scriptPubKey . addresses [ 0 ] ;
_ candidate . region = _ region ;
_ candidate . timestamp = blockInfo . timestamp ;
}
if ( i === decodedTx . outputs . length - 1 ) {
shepherd . log ( ` i received ${ _ candidate . amount } from ${ _ candidate . address } region ${ _ region } ` ) ;
_ rawtx . push ( _ candidate ) ;
resolve ( true ) ;
}
} ) ;
}
}
}
} else {
shepherd . log ( 'elections regular tx' , true ) ;
shepherd . electionsDecodeTx ( decodedTx , ecl , network , _ network , transaction , blockInfo , _ address )
. then ( ( _ regularTx ) => {
if ( _ regularTx [ 0 ] &&
_ regularTx [ 1 ] ) {
_ rawtx . push ( {
address : _ regularTx [ type === 'voter' ? 0 : 1 ] . address || 'self' ,
timestamp : _ regularTx [ type === 'voter' ? 0 : 1 ] . timestamp ,
amount : _ regularTx [ type === 'voter' ? 0 : 1 ] . amount ,
region : 'unknown' ,
regularTx : true ,
hash : transaction [ 'tx_hash' ] ,
} ) ;
} else {
if ( ( type === 'voter' && _ regularTx . type !== 'received' ) && ( type === 'candidate' && _ regularTx . type !== 'sent' ) ) {
_ rawtx . push ( {
address : _ regularTx . address || 'self' ,
timestamp : _ regularTx . timestamp ,
amount : _ regularTx . amount ,
region : 'unknown' ,
regularTx : true ,
hash : transaction [ 'tx_hash' ] ,
} ) ;
}
}
resolve ( true ) ;
} ) ;
}
} ) ;
} else {
_ rawtx . push ( {
address : 'unknown' ,
timestamp : 'cant get block info' ,
amount : 'unknown' ,
region : 'unknown' ,
regularTx : true ,
} ) ;
resolve ( false ) ;
}
} ) ;
} ) ;
} ) )
. then ( promiseResult => {
ecl . close ( ) ;
const successObj = {
msg : 'success' ,
result : _ rawtx ,
} ;
res . end ( JSON . stringify ( successObj ) ) ;
} ) ;
} else {
const successObj = {
msg : 'success' ,
result : [ ] ,
} ;
res . end ( JSON . stringify ( successObj ) ) ;
}
} ) ;
} else {
const errorObj = {
msg : 'error' ,
result : 'unauthorized access' ,
} ;
res . end ( JSON . stringify ( errorObj ) ) ;
}
} ) ;
return shepherd ;
}