Last active
February 1, 2020 05:25
-
-
Save justinmoon/a7bbf738a75e4435ff1f3484a6acdc9b to your computer and use it in GitHub Desktop.
Electrum notes
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Prototype communicating to Electrum server backend | |
// Not currently used | |
const jayson = require('jayson/promise') | |
const bitcoin = require('bitcoinjs-lib') | |
const bip32 = require('bip32') | |
const testnet = bitcoin.networks.testnet | |
function getScriptHash(xpub, index) { | |
const {address} = bitcoin.payments.p2wpkh({ | |
pubkey: bip32 | |
.fromBase58(xpub, testnet) | |
.derive(1) | |
.derive(index).publicKey, | |
network: testnet, | |
}); | |
// FIXME: this is roundabout | |
let script = bitcoin.address.toOutputScript(address, testnet) | |
let hashBuf = bitcoin.crypto.sha256(script) | |
let reversedHashString = hashBuf.toString('hex').match(/.{2}/g).reverse().join("") | |
return reversedHashString | |
} | |
function getScriptHashes(xpub) { | |
let scriptHashes = [] | |
for (let i = 0; i < 20; i += 1) { | |
const scriptHash = getScriptHash(xpub, i) | |
scriptHashes.push(scriptHash) | |
} | |
return scriptHashes | |
} | |
const concatResultReducer = (accumulator, response) => accumulator.concat(response.result) | |
// This is going to need a connection manager if we're working with random public nodes | |
export class ElectrumProtocolBackend { | |
constructor(account) { | |
this.account = account | |
// TODO: maybe we should pass the Account in here so that we can look at signers? | |
this.client = jayson.client.tcp({ | |
host: '68.183.110.103', | |
port: 50001, | |
}) | |
} | |
balances() { | |
// FIXME: jayson must have a batching mode to facilitate this ... | |
let requests = [] | |
const scriptHashes = getScriptHashes(this.account.signers[0].xpub) | |
// each script pubkey | |
for (var scriptHash of scriptHashes) { | |
// call blockchain.scripthash.get_balance | |
let request = this.client.request('blockchain.scripthash.get_balance', [scriptHash]) | |
requests.push(request) | |
} | |
const reducer = (accumulator, response) => ({ | |
confirmed: accumulator.confirmed + response.result.confirmed, | |
unconfirmed: accumulator.unconfirmed + response.result.unconfirmed, | |
}) | |
return Promise.all(requests).then(responses => { | |
return responses.reduce( | |
(accumulator, response) => ({ | |
confirmed: accumulator.confirmed + response.result.confirmed, | |
unconfirmed: accumulator.unconfirmed + response.result.unconfirmed, | |
}), | |
{confirmed: 0, unconfirmed: 0} | |
) | |
}) | |
} | |
utxos() { | |
let requests = [] | |
const scriptHashes = getScriptHashes(this.account.signers[0].xpub) | |
for (var scriptHash of scriptHashes) { | |
let request = this.client.request('blockchain.scripthash.listunspent', [scriptHash]) | |
requests.push(request) | |
} | |
const initial = [] | |
return Promise.all(requests).then(responses => { | |
return responses.reduce(concatResultReducer, initial) | |
}) | |
} | |
async transactions() { | |
// each pubkey | |
// result in blockchain.scripthash.history | |
// result in blockchain.transaction.get (verbose=true) | |
// return Tranasction instance | |
// Fetch txids | |
let historyRequests = [] | |
const scriptHashes = getScriptHashes(this.account.signers[0].xpub) | |
for (var scriptHash of scriptHashes) { | |
let request = this.client.request('blockchain.scripthash.get_history', [scriptHash]) | |
historyRequests.push(request) | |
} | |
const history = await Promise.all(historyRequests).then(responses => { | |
return responses.reduce(concatResultReducer, []) | |
}) | |
// Fetch full transactions | |
const transactionRequests = [] | |
for (var tx of history) { | |
let request = this.client.request('blockchain.transaction.get', [tx.tx_hash, true]) | |
transactionRequests.push(request) | |
} | |
return Promise.all(transactionRequests).then(responses => { | |
return responses.reduce(concatResultReducer, []) | |
}) | |
} | |
broadcast() {} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const bitcoin = require('bitcoinjs-lib'); | |
const testnet = bitcoin.networks.testnet; | |
const mainnet = bitcoin.networks.mainnet; | |
const bip32 = require('bip32'); | |
const jayson = require('jayson/promise') | |
const fs = require('fs') | |
const path = require('path') | |
// Silly hack: https://github.com/request/request/issues/418#issuecomment-17149236 | |
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0" | |
const testnetClient = jayson.client.tcp({ | |
//host: "testnetnode.arihanc.com", | |
//port: 50002, | |
//host: "testnet.hsmiths.com", | |
//port: 53012, | |
host: '68.183.110.103', | |
port: 50001, | |
}) | |
const mainnetClient = jayson.client.tcp({ | |
// mainnet | |
//host: "electrum.hsmiths.com", | |
host: "node.arihanc.com", | |
port: 50001, | |
}) | |
async function getBalancesForAddress(client, address, network) { | |
let script = bitcoin.address.toOutputScript(address, network) | |
console.log(script) | |
let hashBuf = bitcoin.crypto.sha256(script) | |
let scriptHash = hashBuf.toString('hex').match(/.{2}/g).reverse().join("") | |
console.log(scriptHash) | |
client.request('blockchain.scripthash.get_balance', [scriptHash]).then(console.log).catch(console.error) | |
} | |
const mainnetAddress = '17A16QmavnUfCW11DAApiJxp7ARnxN5pGX' | |
//const testnetAddress = '2Mt9iSWNS6eXPeZ5tGo3uJSkGzobMzqEiKa' | |
const testnetAddress = 'tb1qgvyn7zyl329m663lpgdw042hqslmfsndugnwnm' | |
function getMainnetBalance() { | |
getBalancesForAddress(mainnetClient, mainnetAddress, mainnet) | |
} | |
function sendVersion(client) { | |
client.request('server.version', ["2.7.11", "1.4"]) | |
} | |
function getTestnetBalance() { | |
sendVersion(testnetClient) | |
getBalancesForAddress(testnetClient, testnetAddress, testnet) | |
} | |
//getMainnetBalance() | |
getTestnetBalance() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Everything is testnet for now | |
// | |
const bitcoin = require('bitcoinjs-lib'); | |
const testnet = bitcoin.networks.testnet; | |
const mainnet = bitcoin.networks.mainnet; | |
const bip32 = require('bip32'); | |
const ElectrumProtocolClient = require('./electrum.js') | |
const jayson = require('jayson/promise') | |
const client = jayson.client.tcp({ | |
// mainnet | |
//host: "electrum.hsmiths.com", | |
//host: "node.arihanc.com", | |
// testnet | |
//host: "testnet.hsmiths.com", | |
//host: "testnet1.bauerj.eu", | |
//host: "testnet.qtornado.com", | |
host: "bitcoin-test.networkingfanatic.com", | |
port: 50001, | |
}) | |
async function getBalancesForAddress(address) { | |
let script = bitcoin.address.toOutputScript(address, mainnet) | |
console.log(script) | |
let hashBuf = bitcoin.crypto.sha256(script) | |
let scriptHash = hashBuf.toString('hex').match(/.{2}/g).reverse().join("") | |
console.log(scriptHash) | |
client.request('blockchain.scripthash.get_balance', [scriptHash]).then(console.log).catch(console.error) | |
} | |
// should equal 8b01df4e368ea28f8dc0423bcf7a4923e3a12d307c875e47a0cfbf90b5c39161 | |
//console.log(getBalancesForAddress('1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa')) | |
// mine | |
//const myaddress = 'tb1qgvyn7zyl329m663lpgdw042hqslmfsndugnwnm' | |
// Random mainnet addresses | |
//const myaddress = '1521WZxZnReQ6H3TCHh5nBjaRu3HPXM2NX' | |
//const myaddress = 'bc1q62x32j8kkvzdjzy8sulduj7ft4czu5tq6w8f4d' | |
//const myaddress = '1EYTGtG4LnFfiMvjJdsU7GMGCQvsRSjYhx' | |
//const myaddress = '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa' | |
// Random testnet address | |
const myaddress = '2Mt9iSWNS6eXPeZ5tGo3uJSkGzobMzqEiKa' | |
//getBalancesForAddress(myaddress) | |
// works | |
//client.request( | |
//'blockchain.scripthash.get_balance', | |
//['8b01df4e368ea28f8dc0423bcf7a4923e3a12d307c875e47a0cfbf90b5c39161'], | |
//).then(console.log).catch(console.error) | |
function getScriptHash(xpub, index) { | |
const {address} = bitcoin.payments.p2wpkh({ | |
pubkey: bip32 | |
.fromBase58(xpub, testnet) | |
.derive(1) | |
.derive(index).publicKey, | |
network: testnet, | |
}); | |
console.log(address) | |
// FIXME: this is roundabout | |
let script = bitcoin.address.toOutputScript(address, testnet) | |
let hashBuf = bitcoin.crypto.sha256(script) | |
return hashBuf.toString('hex') | |
} | |
function getScriptHashes(xpub) { | |
let scriptHashes = [] | |
for (let i = 0; i < 20; i += 1) { | |
const scriptHash = getScriptHash(xpub, i) | |
scriptHashes.push(scriptHash) | |
} | |
return scriptHashes | |
} | |
// Fetch the first 20 balances for this xpub | |
function getBalances(xpub) { | |
const scriptHashes = getScriptHashes(xpub) | |
let requests = [] | |
for (let i = 0; i < scriptHashes.length; i++) { | |
const scriptHash = scriptHashes[i] | |
const request = client.request('blockchain.scripthash.get_balance', [scriptHash]) | |
requests.push(request) | |
} | |
const reducer = (accumulator, response) => { | |
console.log(response) | |
return ({ | |
confirmed: accumulator.confirmed + response.result.confirmed, | |
unconfirmed: accumulator.unconfirmed + response.result.unconfirmed, | |
}) | |
} | |
const initial = {confirmed: 0, unconfirmed: 0} | |
return Promise.all(requests).then(responses => { | |
return responses.reduce(reducer, initial) | |
}) | |
} | |
//getBalances().then(console.log) | |
const XPRV = "tprv8ZgxMBicQKsPeCXRXf7d8ibQiXrei23kAa3tPkH7aKg33LFrtG6JhF3zQCiy8ADzoEr6C9Kj7PCq23Lehq1redvYpYnCSS6Ledt6CwiXTUx" | |
const XPUB = 'tpubD6NzVbkrYhZ4XfZDRJnDY8FXHZNasMEejsefgGKQzbURspWdWeutsjfraKQqpmVJUKDHdzuXPKzJ2U1gLSsHqhg1qPZhYn4hTyYt5r2dfHp' | |
const FINGERPRINT = '41cdd223' | |
function getAddress(index) { | |
const pubkey = bip32 | |
.fromBase58(XPRV, testnet) | |
.derive(1) | |
.derive(index) | |
const {address} = bitcoin.payments.p2wpkh({ | |
pubkey: pubkey.publicKey, | |
network: testnet, | |
}) | |
return address | |
} | |
function xprvToXpub(xprv) { | |
return bip32.fromBase58(XPRV, testnet).neutered().toBase58() | |
} | |
function getUtxos(xpub) { | |
return [] | |
} | |
function getTransactions(xpub) { | |
return [] | |
} | |
//getBalances(XPRV).then(console.log) | |
module.exports = { | |
getBalances, | |
getUtxos, | |
getTransactions, | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment