2021-03-09 12:26:56 +01:00
import BigNumber from 'bignumber.js' ;
import bitcoinMessage from 'bitcoinjs-message' ;
2020-05-24 12:27:08 +02:00
import { randomBytes } from '../rng' ;
2018-03-24 22:24:20 +01:00
import { AbstractWallet } from './abstract-wallet' ;
2020-05-24 12:27:08 +02:00
import { HDSegwitBech32Wallet } from '..' ;
2019-09-14 00:15:59 +02:00
const bitcoin = require ( 'bitcoinjs-lib' ) ;
2020-07-01 13:56:52 +02:00
const BlueElectrum = require ( '../../blue_modules/BlueElectrum' ) ;
2021-05-10 17:01:28 +02:00
const coinSelect = require ( 'coinselect' ) ;
2020-04-22 17:13:18 +02:00
const coinSelectSplit = require ( 'coinselect/split' ) ;
2018-03-20 21:41:07 +01:00
/ * *
2018-12-22 17:51:07 +01:00
* Has private key and single address like "1ABCD....."
2018-03-20 21:41:07 +01:00
* ( legacy P2PKH compressed )
* /
export class LegacyWallet extends AbstractWallet {
2018-12-28 16:52:06 +01:00
static type = 'legacy' ;
static typeReadable = 'Legacy (P2PKH)' ;
2018-03-20 21:41:07 +01:00
2018-07-14 22:32:36 +02:00
/ * *
* Simple function which says that we havent tried to fetch balance
* for a long time
*
* @ return { boolean }
* /
timeToRefreshBalance ( ) {
2018-07-14 21:52:27 +02:00
if ( + new Date ( ) - this . _lastBalanceFetch >= 5 * 60 * 1000 ) {
2018-07-02 15:51:24 +02:00
return true ;
}
2018-07-14 22:32:36 +02:00
return false ;
}
2018-07-12 01:38:24 +02:00
2018-07-14 22:32:36 +02:00
/ * *
* Simple function which says if we hve some low - confirmed transactions
* and we better fetch them
*
* @ return { boolean }
* /
timeToRefreshTransaction ( ) {
2020-06-01 14:54:23 +02:00
for ( const tx of this . getTransactions ( ) ) {
2021-04-27 21:15:41 +02:00
if ( tx . confirmations < 7 && this . _lastTxFetch < + new Date ( ) - 5 * 60 * 1000 ) {
2018-07-12 01:38:24 +02:00
return true ;
}
}
2018-07-14 22:32:36 +02:00
return false ;
2018-07-02 15:51:24 +02:00
}
2018-12-11 23:52:46 +01:00
async generate ( ) {
2020-05-09 09:21:45 +02:00
const buf = await randomBytes ( 32 ) ;
2020-05-01 02:36:52 +02:00
this . secret = bitcoin . ECPair . makeRandom ( { rng : ( ) => buf } ) . toWIF ( ) ;
2018-03-20 21:41:07 +01:00
}
2020-06-29 14:58:43 +02:00
async generateFromEntropy ( user ) {
let i = 0 ;
do {
i += 1 ;
const random = await randomBytes ( user . length < 32 ? 32 - user . length : 0 ) ;
const buf = Buffer . concat ( [ user , random ] , 32 ) ;
try {
this . secret = bitcoin . ECPair . fromPrivateKey ( buf ) . toWIF ( ) ;
return ;
} catch ( e ) {
if ( i === 5 ) throw e ;
}
} while ( true ) ;
}
2018-03-20 21:41:07 +01:00
/ * *
*
* @ returns { string }
* /
getAddress ( ) {
if ( this . _address ) return this . _address ;
let address ;
try {
2020-06-01 14:54:23 +02:00
const keyPair = bitcoin . ECPair . fromWIF ( this . secret ) ;
2019-09-14 00:15:59 +02:00
address = bitcoin . payments . p2pkh ( {
pubkey : keyPair . publicKey ,
} ) . address ;
2018-03-20 21:41:07 +01:00
} catch ( err ) {
return false ;
}
this . _address = address ;
return this . _address ;
}
2020-07-29 22:00:00 +02:00
/ * *
* @ inheritDoc
* /
getAllExternalAddresses ( ) {
return [ this . getAddress ( ) ] ;
}
2018-05-20 11:38:50 +02:00
/ * *
2018-06-17 12:46:19 +02:00
* Fetches balance of the Wallet via API .
* Returns VOID . Get the actual balance via getter .
2018-05-20 11:38:50 +02:00
*
* @ returns { Promise . < void > }
* /
2018-03-20 21:41:07 +01:00
async fetchBalance ( ) {
try {
2020-06-01 14:54:23 +02:00
const balance = await BlueElectrum . getBalanceByAddress ( this . getAddress ( ) ) ;
2020-03-09 19:51:34 +01:00
this . balance = Number ( balance . confirmed ) ;
2020-04-22 17:13:18 +02:00
this . unconfirmed _balance = Number ( balance . unconfirmed ) ;
2018-07-02 11:48:40 +02:00
this . _lastBalanceFetch = + new Date ( ) ;
2020-03-09 19:51:34 +01:00
} catch ( Error ) {
console . warn ( Error ) ;
2018-03-20 21:41:07 +01:00
}
}
2018-06-17 12:46:19 +02:00
/ * *
* Fetches UTXO from API . Returns VOID .
*
* @ return { Promise . < void > }
* /
2018-03-20 21:41:07 +01:00
async fetchUtxo ( ) {
try {
2020-06-01 14:54:23 +02:00
const utxos = await BlueElectrum . multiGetUtxoByAddress ( [ this . getAddress ( ) ] ) ;
2020-03-31 18:46:31 +02:00
this . utxo = [ ] ;
2020-06-01 14:54:23 +02:00
for ( const arr of Object . values ( utxos ) ) {
2020-03-09 19:51:34 +01:00
this . utxo = this . utxo . concat ( arr ) ;
}
2020-04-22 17:13:18 +02:00
// now we need to fetch txhash for each input as required by PSBT
if ( LegacyWallet . type !== this . type ) return ; // but only for LEGACY single-address wallets
2020-06-01 14:54:23 +02:00
const txhexes = await BlueElectrum . multiGetTransactionByTxid (
this . utxo . map ( u => u . txId ) ,
2020-04-22 17:13:18 +02:00
50 ,
false ,
) ;
2020-06-01 14:54:23 +02:00
const newUtxos = [ ] ;
for ( const u of this . utxo ) {
2020-04-22 17:13:18 +02:00
if ( txhexes [ u . txId ] ) u . txhex = txhexes [ u . txId ] ;
newUtxos . push ( u ) ;
}
this . utxo = newUtxos ;
2020-03-09 19:51:34 +01:00
} catch ( Error ) {
console . warn ( Error ) ;
}
2018-03-20 21:41:07 +01:00
}
2020-11-22 08:43:11 +01:00
/ * *
* Getter for previously fetched UTXO . For example :
* [ { height : 0 ,
* value : 666 ,
* address : 'string' ,
* txId : 'string' ,
* vout : 1 ,
* txid : 'string' ,
* amount : 666 ,
* wif : 'string' ,
* confirmations : 0 } ]
*
* @ param respectFrozen { boolean } Add Frozen outputs
* @ returns { [ ] }
* /
getUtxo ( respectFrozen = false ) {
2020-10-23 12:27:03 +02:00
let ret = [ ] ;
2020-06-01 14:54:23 +02:00
for ( const u of this . utxo ) {
2020-04-22 17:13:18 +02:00
if ( u . txId ) u . txid = u . txId ;
if ( ! u . confirmations && u . height ) u . confirmations = BlueElectrum . estimateCurrentBlockheight ( ) - u . height ;
ret . push ( u ) ;
}
2021-01-25 16:29:12 +01:00
if ( ret . length === 0 ) {
ret = this . getDerivedUtxoFromOurTransaction ( ) ; // oy vey, no stored utxo. lets attempt to derive it from stored transactions
}
2020-11-22 08:43:11 +01:00
if ( ! respectFrozen ) {
2020-10-25 10:04:04 +01:00
ret = ret . filter ( ( { txid , vout } ) => ! this . getUTXOMetadata ( txid , vout ) . frozen ) ;
2020-10-23 12:27:03 +02:00
}
2020-04-22 17:13:18 +02:00
return ret ;
2020-03-09 19:51:34 +01:00
}
2021-01-25 16:29:12 +01:00
getDerivedUtxoFromOurTransaction ( returnSpentUtxoAsWell = false ) {
const utxos = [ ] ;
const ownedAddressesHashmap = { } ;
ownedAddressesHashmap [ this . getAddress ( ) ] = true ;
/ * *
* below copypasted from
* @ see AbstractHDElectrumWallet . getDerivedUtxoFromOurTransaction
* /
for ( const tx of this . getTransactions ( ) ) {
for ( const output of tx . outputs ) {
let address = false ;
if ( output . scriptPubKey && output . scriptPubKey . addresses && output . scriptPubKey . addresses [ 0 ] ) {
address = output . scriptPubKey . addresses [ 0 ] ;
}
if ( ownedAddressesHashmap [ address ] ) {
const value = new BigNumber ( output . value ) . multipliedBy ( 100000000 ) . toNumber ( ) ;
utxos . push ( {
txid : tx . txid ,
txId : tx . txid ,
vout : output . n ,
address ,
value ,
amount : value ,
confirmations : tx . confirmations ,
wif : false ,
height : BlueElectrum . estimateCurrentBlockheight ( ) - tx . confirmations ,
} ) ;
}
}
}
if ( returnSpentUtxoAsWell ) return utxos ;
// got all utxos we ever had. lets filter out the ones that are spent:
const ret = [ ] ;
for ( const utxo of utxos ) {
let spent = false ;
for ( const tx of this . getTransactions ( ) ) {
for ( const input of tx . inputs ) {
if ( input . txid === utxo . txid && input . vout === utxo . vout ) spent = true ;
// utxo we got previously was actually spent right here ^^
}
}
if ( ! spent ) {
ret . push ( utxo ) ;
}
}
return ret ;
}
2018-06-17 12:46:19 +02:00
/ * *
2020-03-09 19:51:34 +01:00
* Fetches transactions via Electrum . Returns VOID .
* Use getter to get the actual list . *
* @ see AbstractHDElectrumWallet . fetchTransactions ( )
2018-06-17 12:46:19 +02:00
*
* @ return { Promise . < void > }
* /
2018-03-20 21:41:07 +01:00
async fetchTransactions ( ) {
2020-03-09 19:51:34 +01:00
// Below is a simplified copypaste from HD electrum wallet
2020-12-08 14:00:09 +01:00
const _txsByExternalIndex = [ ] ;
2020-06-01 14:54:23 +02:00
const addresses2fetch = [ this . getAddress ( ) ] ;
2020-03-09 19:51:34 +01:00
// first: batch fetch for all addresses histories
2020-06-01 14:54:23 +02:00
const histories = await BlueElectrum . multiGetHistoryByAddress ( addresses2fetch ) ;
const txs = { } ;
for ( const history of Object . values ( histories ) ) {
for ( const tx of history ) {
2020-03-09 19:51:34 +01:00
txs [ tx . tx _hash ] = tx ;
2018-03-20 21:41:07 +01:00
}
2020-03-09 19:51:34 +01:00
}
2018-03-20 21:41:07 +01:00
2020-03-09 19:51:34 +01:00
// next, batch fetching each txid we got
2020-06-01 14:54:23 +02:00
const txdatas = await BlueElectrum . multiGetTransactionByTxid ( Object . keys ( txs ) ) ;
2018-07-25 01:27:21 +02:00
2020-03-09 19:51:34 +01:00
// now, tricky part. we collect all transactions from inputs (vin), and batch fetch them too.
// then we combine all this data (we need inputs to see source addresses and amounts)
2020-06-01 14:54:23 +02:00
const vinTxids = [ ] ;
for ( const txdata of Object . values ( txdatas ) ) {
for ( const vin of txdata . vin ) {
2020-03-09 19:51:34 +01:00
vinTxids . push ( vin . txid ) ;
}
}
2020-06-01 14:54:23 +02:00
const vintxdatas = await BlueElectrum . multiGetTransactionByTxid ( vinTxids ) ;
2020-03-09 19:51:34 +01:00
// fetched all transactions from our inputs. now we need to combine it.
// iterating all _our_ transactions:
2020-06-01 14:54:23 +02:00
for ( const txid of Object . keys ( txdatas ) ) {
2020-03-09 19:51:34 +01:00
// iterating all inputs our our single transaction:
for ( let inpNum = 0 ; inpNum < txdatas [ txid ] . vin . length ; inpNum ++ ) {
2020-06-01 14:54:23 +02:00
const inpTxid = txdatas [ txid ] . vin [ inpNum ] . txid ;
const inpVout = txdatas [ txid ] . vin [ inpNum ] . vout ;
2020-03-09 19:51:34 +01:00
// got txid and output number of _previous_ transaction we shoud look into
if ( vintxdatas [ inpTxid ] && vintxdatas [ inpTxid ] . vout [ inpVout ] ) {
// extracting amount & addresses from previous output and adding it to _our_ input:
txdatas [ txid ] . vin [ inpNum ] . addresses = vintxdatas [ inpTxid ] . vout [ inpVout ] . scriptPubKey . addresses ;
txdatas [ txid ] . vin [ inpNum ] . value = vintxdatas [ inpTxid ] . vout [ inpVout ] . value ;
2018-03-20 21:41:07 +01:00
}
}
}
2020-03-09 19:51:34 +01:00
// now, we need to put transactions in all relevant `cells` of internal hashmaps: this.transactions_by_internal_index && this.transactions_by_external_index
2018-10-11 19:25:39 +02:00
2020-06-01 14:54:23 +02:00
for ( const tx of Object . values ( txdatas ) ) {
for ( const vin of tx . vin ) {
2020-03-09 19:51:34 +01:00
if ( vin . addresses && vin . addresses . indexOf ( this . getAddress ( ) ) !== - 1 ) {
// this TX is related to our address
2020-06-01 14:54:23 +02:00
const clonedTx = Object . assign ( { } , tx ) ;
2020-03-09 19:51:34 +01:00
clonedTx . inputs = tx . vin . slice ( 0 ) ;
clonedTx . outputs = tx . vout . slice ( 0 ) ;
delete clonedTx . vin ;
delete clonedTx . vout ;
2018-10-11 19:25:39 +02:00
2020-12-08 14:00:09 +01:00
_txsByExternalIndex . push ( clonedTx ) ;
2020-03-09 19:51:34 +01:00
}
2018-10-11 19:25:39 +02:00
}
2020-06-01 14:54:23 +02:00
for ( const vout of tx . vout ) {
2020-05-18 21:20:50 +02:00
if ( vout . scriptPubKey . addresses && vout . scriptPubKey . addresses . indexOf ( this . getAddress ( ) ) !== - 1 ) {
2020-03-09 19:51:34 +01:00
// this TX is related to our address
2020-06-01 14:54:23 +02:00
const clonedTx = Object . assign ( { } , tx ) ;
2020-03-09 19:51:34 +01:00
clonedTx . inputs = tx . vin . slice ( 0 ) ;
clonedTx . outputs = tx . vout . slice ( 0 ) ;
delete clonedTx . vin ;
delete clonedTx . vout ;
2020-12-08 14:00:09 +01:00
_txsByExternalIndex . push ( clonedTx ) ;
2020-03-09 19:51:34 +01:00
}
2018-10-11 19:25:39 +02:00
}
2020-03-09 19:51:34 +01:00
}
2018-10-11 19:25:39 +02:00
2020-12-08 14:00:09 +01:00
this . _txs _by _external _index = _txsByExternalIndex ;
2020-03-09 19:51:34 +01:00
this . _lastTxFetch = + new Date ( ) ;
2018-10-11 19:25:39 +02:00
}
2020-03-09 19:51:34 +01:00
getTransactions ( ) {
// a hacky code reuse from electrum HD wallet:
this . _txs _by _external _index = this . _txs _by _external _index || [ ] ;
this . _txs _by _internal _index = [ ] ;
2018-10-11 19:25:39 +02:00
2020-06-01 14:54:23 +02:00
const hd = new HDSegwitBech32Wallet ( ) ;
2020-03-09 19:51:34 +01:00
return hd . getTransactions . apply ( this ) ;
2018-10-11 19:25:39 +02:00
}
2020-04-28 18:27:35 +02:00
/ * *
* Broadcast txhex . Can throw an exception if failed
*
* @ param { String } txhex
* @ returns { Promise < boolean > }
* /
2018-03-20 21:41:07 +01:00
async broadcastTx ( txhex ) {
2020-06-01 14:54:23 +02:00
const broadcast = await BlueElectrum . broadcastV2 ( txhex ) ;
2020-04-28 18:27:35 +02:00
console . log ( { broadcast } ) ;
if ( broadcast . indexOf ( 'successfully' ) !== - 1 ) return true ;
return broadcast . length === 64 ; // this means return string is txid (precise length), so it was broadcasted ok
2018-06-11 21:17:16 +02:00
}
2020-09-14 12:49:08 +02:00
coinselect ( utxos , targets , feeRate , changeAddress ) {
2020-04-22 17:13:18 +02:00
if ( ! changeAddress ) throw new Error ( 'No change address provided' ) ;
2021-05-10 17:01:28 +02:00
let algo = coinSelect ;
2020-12-24 14:36:28 +01:00
// if targets has output without a value, we want send MAX to it
if ( targets . some ( i => ! ( 'value' in i ) ) ) {
2020-04-22 17:13:18 +02:00
algo = coinSelectSplit ;
2018-05-20 11:38:50 +02:00
}
2020-04-22 17:13:18 +02:00
2020-06-01 14:54:23 +02:00
const { inputs , outputs , fee } = algo ( utxos , targets , feeRate ) ;
2020-04-22 17:13:18 +02:00
// .inputs and .outputs will be undefined if no solution was found
if ( ! inputs || ! outputs ) {
2020-12-24 14:36:28 +01:00
throw new Error ( 'Not enough balance. Try sending smaller amount or decrease the fee.' ) ;
2020-04-22 17:13:18 +02:00
}
2020-09-14 12:49:08 +02:00
return { inputs , outputs , fee } ;
}
2020-04-22 17:13:18 +02:00
2020-09-14 12:49:08 +02:00
/ * *
*
* @ param utxos { Array . < { vout : Number , value : Number , txId : String , address : String , txhex : String , } > } List of spendable utxos
* @ param targets { Array . < { value : Number , address : String } > } Where coins are going . If theres only 1 target and that target has no value - this will send MAX to that address ( respecting fee rate )
* @ param feeRate { Number } satoshi per byte
* @ param changeAddress { String } Excessive coins will go back to that address
* @ param sequence { Number } Used in RBF
* @ param skipSigning { boolean } Whether we should skip signing , use returned ` psbt ` in that case
* @ param masterFingerprint { number } Decimal number of wallet ' s master fingerprint
* @ returns { { outputs : Array , tx : Transaction , inputs : Array , fee : Number , psbt : Psbt } }
* /
createTransaction ( utxos , targets , feeRate , changeAddress , sequence , skipSigning = false , masterFingerprint ) {
2020-09-14 19:24:27 +02:00
if ( targets . length === 0 ) throw new Error ( 'No destination provided' ) ;
2020-09-14 12:49:08 +02:00
const { inputs , outputs , fee } = this . coinselect ( utxos , targets , feeRate , changeAddress ) ;
sequence = sequence || 0xffffffff ; // disable RBF by default
const psbt = new bitcoin . Psbt ( ) ;
2020-04-22 17:13:18 +02:00
let c = 0 ;
2020-06-01 14:54:23 +02:00
const values = { } ;
2020-04-22 17:13:18 +02:00
let keyPair ;
inputs . forEach ( input => {
if ( ! skipSigning ) {
// skiping signing related stuff
keyPair = bitcoin . ECPair . fromWIF ( this . secret ) ; // secret is WIF
}
values [ c ] = input . value ;
c ++ ;
if ( ! input . txhex ) throw new Error ( 'UTXO is missing txhex of the input, which is required by PSBT for non-segwit input' ) ;
psbt . addInput ( {
hash : input . txid ,
index : input . vout ,
sequence ,
// non-segwit inputs now require passing the whole previous tx as Buffer
nonWitnessUtxo : Buffer . from ( input . txhex , 'hex' ) ,
} ) ;
} ) ;
outputs . forEach ( output => {
// if output has no address - this is change output
if ( ! output . address ) {
output . address = changeAddress ;
}
2020-06-01 14:54:23 +02:00
const outputData = {
2020-04-22 17:13:18 +02:00
address : output . address ,
value : output . value ,
} ;
psbt . addOutput ( outputData ) ;
} ) ;
if ( ! skipSigning ) {
// skiping signing related stuff
for ( let cc = 0 ; cc < c ; cc ++ ) {
psbt . signInput ( cc , keyPair ) ;
}
}
let tx ;
if ( ! skipSigning ) {
tx = psbt . finalizeAllInputs ( ) . extractTransaction ( ) ;
}
return { tx , inputs , outputs , fee , psbt } ;
2018-05-20 11:38:50 +02:00
}
2018-06-17 12:46:44 +02:00
2018-06-25 00:22:46 +02:00
getLatestTransactionTime ( ) {
2018-09-01 01:28:19 +02:00
if ( this . getTransactions ( ) . length === 0 ) {
return 0 ;
}
let max = 0 ;
2020-06-01 14:54:23 +02:00
for ( const tx of this . getTransactions ( ) ) {
2018-09-01 01:28:19 +02:00
max = Math . max ( new Date ( tx . received ) * 1 , max ) ;
2018-06-25 00:22:46 +02:00
}
2018-09-01 01:28:19 +02:00
return new Date ( max ) . toString ( ) ;
2018-06-25 00:22:46 +02:00
}
2020-03-09 19:51:34 +01:00
/ * *
* Validates any address , including legacy , p2sh and bech32
*
* @ param address
* @ returns { boolean }
* /
2018-07-12 01:38:24 +02:00
isAddressValid ( address ) {
try {
bitcoin . address . toOutputScript ( address ) ;
return true ;
} catch ( e ) {
return false ;
}
}
2020-03-09 19:51:34 +01:00
2020-03-23 17:32:51 +01:00
/ * *
* Converts script pub key to legacy address if it can . Returns FALSE if it cant .
*
* @ param scriptPubKey
* @ returns { boolean | string } Either p2pkh address or false
* /
static scriptPubKeyToAddress ( scriptPubKey ) {
try {
2021-02-24 19:21:37 +01:00
const scriptPubKey2 = Buffer . from ( scriptPubKey , 'hex' ) ;
return bitcoin . payments . p2pkh ( {
2020-03-23 17:32:51 +01:00
output : scriptPubKey2 ,
network : bitcoin . networks . bitcoin ,
} ) . address ;
} catch ( _ ) {
return false ;
}
}
2020-03-09 19:51:34 +01:00
weOwnAddress ( address ) {
2021-05-19 17:52:56 +02:00
let cleanAddress = address ;
if ( this . segwitType === 'p2wpkh' ) {
cleanAddress = address . toLowerCase ( ) ;
}
return this . getAddress ( ) === cleanAddress || this . _address === cleanAddress ;
2020-03-09 19:51:34 +01:00
}
2020-04-22 17:13:18 +02:00
2020-08-10 16:17:50 +02:00
weOwnTransaction ( txid ) {
for ( const tx of this . getTransactions ( ) ) {
if ( tx && tx . txid && tx . txid === txid ) return true ;
}
return false ;
}
2021-03-09 12:26:56 +01:00
allowSignVerifyMessage ( ) {
return true ;
}
2020-11-22 09:19:52 +01:00
/ * *
* Check if address is a Change address . Needed for Coin control .
* Useless for Legacy wallets , so it is always false
*
* @ param address
* @ returns { Boolean } Either address is a change or not
* /
2020-10-29 19:42:40 +01:00
addressIsChange ( address ) {
2020-11-09 11:32:51 +01:00
return false ;
2020-10-29 19:42:40 +01:00
}
2021-03-09 12:26:56 +01:00
2021-03-11 11:45:49 +01:00
/ * *
* Finds WIF corresponding to address and returns it
*
* @ param address { string } Address that belongs to this wallet
* @ returns { string | false } WIF or false
* /
_getWIFbyAddress ( address ) {
return this . getAddress ( ) === address ? this . secret : null ;
}
2021-03-09 12:26:56 +01:00
2021-03-11 11:45:49 +01:00
/ * *
* Signes text message using address private key and returs signature
*
* @ param message { string }
* @ param address { string }
* @ returns { string } base64 encoded signature
* /
2021-04-15 19:46:10 +02:00
signMessage ( message , address , useSegwit = true ) {
2021-03-11 11:45:49 +01:00
const wif = this . _getWIFbyAddress ( address ) ;
if ( wif === null ) throw new Error ( 'Invalid address' ) ;
const keyPair = bitcoin . ECPair . fromWIF ( wif ) ;
2021-03-09 12:26:56 +01:00
const privateKey = keyPair . privateKey ;
2021-04-15 19:46:10 +02:00
const options = this . segwitType && useSegwit ? { segwitType : this . segwitType } : undefined ;
2021-03-09 12:26:56 +01:00
const signature = bitcoinMessage . sign ( message , privateKey , keyPair . compressed , options ) ;
return signature . toString ( 'base64' ) ;
}
2021-03-11 11:45:49 +01:00
/ * *
* Verifies text message signature by address
*
* @ param message { string }
* @ param address { string }
* @ param signature { string }
* @ returns { boolean } base64 encoded signature
* /
2021-03-09 12:26:56 +01:00
verifyMessage ( message , address , signature ) {
// null, true so it can verify Electrum signatores without errors
return bitcoinMessage . verify ( message , address , signature , null , true ) ;
}
2021-03-25 16:28:25 +01:00
/ * *
* Probes address for transactions , if there are any returns TRUE
*
* @ returns { Promise < boolean > }
* /
async wasEverUsed ( ) {
const txs = await BlueElectrum . getTransactionsByAddress ( this . getAddress ( ) ) ;
return txs . length > 0 ;
}
2018-03-20 21:41:07 +01:00
}