Last active
November 24, 2021 10:55
-
-
Save roshnet/3eba1e3a8e246a4a8df31c3235153fcd to your computer and use it in GitHub Desktop.
Implementing the given methods in the Wallet class
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
/* | |
Mnemoics used - | |
quality armor buddy double food laugh tunnel marine lizard west cup what basket lumber walnut link frog rice pigeon abstract nurse volcano curve twice | |
Generated tpub from iancoleman.io/bip32 | |
tpubDC93eCC1ySXoBp7AKVv9M9uRi4evZjwgd8LbmYuhXs6NnarvhHsNFPcrzwPqsrUa3y5E5FjnbGE4Li55Y5G96aaPJsb2DKagQC8zgpcRcMQ | |
Generated Account extended private key from iancoleman.io/bip32 | |
tprv8fT1Vn9mq4r8JM5NRrFYwkFK938zQQkn3pjpV2sQ7bHyx6cA4u3n4tzzpn9vJysFzvbLW2VSUDgG9bPQhxGKhfxvyc8wVMahKNFVPL8aMqv | |
*/ | |
const bjl = require('bitcoinjs-lib') | |
const axios = require('axios').default | |
const BIP32Factory = require('bip32').default | |
const coinselect = require('coinselect') | |
const BLOCKCYPHER_API_ROOT = 'https://api.blockcypher.com' | |
const feeRate = 55 | |
class Wallet { | |
constructor(network) { | |
this.network = network | |
this.token = 'd6c3025e283c468e8b7c5268cd5b550f' | |
} | |
// Generate bitcoin testnet addresses using "xpub" for "chain" index = 0 or 1 from range index "start" to "end". | |
async address_list(xpub, chain = null, start = 0, end = 1) { | |
const ecc = await import('tiny-secp256k1') | |
const bip32 = await BIP32Factory(ecc) | |
let node = bip32.fromBase58(xpub, this.network) | |
const { address } = bjl.payments.p2pkh({ | |
pubkey: node.derive(start).derive(end).publicKey, | |
network: this.network, | |
}) | |
return address | |
} | |
// Add the "addresses" list on blockcypher database. This list is recognised by the "name" argument. | |
async add_wallet(name, addresses) { | |
const endpoint = new URL('/v1/btc/test3/wallets', BLOCKCYPHER_API_ROOT) | |
endpoint.searchParams.set('token', this.token) | |
try { | |
const response = await axios.post(endpoint.href, { name, addresses }) | |
return response.data | |
} catch (e) { | |
throw new Error(e.message) | |
} | |
} | |
// Add the "addresses" on blockcypher database to an already existing wallet recognised by the "name" argument. | |
add_addresses(name, addresses) { | |
const endpoint = new URL( | |
`/v1/btc/test3/wallets/${name}/addresses`, | |
BLOCKCYPHER_API_ROOT, | |
) | |
endpoint.searchParams.set('token', this.token) | |
axios | |
.post(endpoint.href) | |
.then(({ data }) => { | |
console.log('Added', data['addresses'], 'to wallet', name) | |
}) | |
.catch((e) => { | |
console.error(e.message) | |
}) | |
} | |
// Fetch the "addresses" from blockcypher database of an already existing wallet recognised by the "name" argument. | |
async fetch_wallet(name) { | |
const endpoint = new URL( | |
`/v1/btc/test3/wallets/${name}`, | |
BLOCKCYPHER_API_ROOT, | |
) | |
endpoint.searchParams.set('token', this.token) | |
try { | |
const response = await axios.get(endpoint.href) | |
return response.data.addresses | |
} catch (e) { | |
throw new Error(e.message) | |
} | |
} | |
// Fetch "UTXOs" using wallet name provided in "receive" and "change" argumnets using blockcypher APIs | |
async fetch_utxo(walletName, receive, change) { | |
const addresses = await this.fetch_wallet(walletName) | |
const utxos = [] | |
for (let addr of addresses) { | |
const endpoint = new URL( | |
`/v1/btc/test3/addrs/${addr}`, | |
BLOCKCYPHER_API_ROOT, | |
) | |
endpoint.searchParams.set('unspentOnly', true) | |
const response = await axios.get(endpoint.href) | |
utxos.push(response.data) | |
} | |
return utxos | |
} | |
// Generate unsigned txn using "xpub" to send "amount" to "output_address" | |
async generate_unsigned_transaction( | |
xpub, | |
outputAddress, | |
amount, | |
config = { index: 1 }, | |
) { | |
const inputAddress = await this.address_list(xpub, null, config['index']) | |
const endpoint = new URL( | |
'/v1/btc/test3/txs/new', | |
'https://api.blockcypher.com', | |
) | |
const txPayload = { | |
inputs: [{ addresses: [inputAddress] }], | |
outputs: [ | |
{ | |
addresses: [outputAddress], | |
value: amount, | |
}, | |
], | |
} | |
const response = await axios.post(endpoint.href, JSON.stringify(txPayload)) | |
const txResponse = response.data | |
let txId = txResponse['tx']['hash'] | |
const tx = new bjl.Psbt({ network: bjl.networks.testnet }) | |
const txInput = { | |
hash: txId, | |
index: txResponse['tx']['inputs'][0]['output_index'], | |
} | |
const txOutput = { | |
address: outputAddress, | |
value: amount, | |
} | |
let { inputs, outputs, fee } = coinselect([txInput], [txOutput], feeRate) | |
// Remove below condition to create raw unsigned TX | |
if (!inputs || !outputs) throw new Error('Inputs or outputs not generated') | |
tx.addInput(txInput) | |
tx.addOutput(txOutput) | |
return tx.toHex() | |
} | |
} | |
async function main() { | |
const w = new Wallet(bjl.networks.testnet) | |
// const tx = await w.generate_unsigned_transaction( | |
// 'tpubDC93eCC1ySXoBp7AKVv9M9uRi4evZjwgd8LbmYuhXs6NnarvhHsNFPcrzwPqsrUa3y5E5FjnbGE4Li55Y5G96aaPJsb2DKagQC8zgpcRcMQ', | |
// 'n1oAxbBijCqVDYhfmxkW6CzR7abTx6zoud', | |
// 50000, | |
// { index: 1 }, | |
// ) | |
// console.log('[OK] Created TX', tx) | |
const utxo = await w.fetch_utxo('rosh0', 'n1oAxbBijCqVDYhfmxkW6CzR7abTx6zoud') | |
console.log(utxo) | |
} | |
main().catch((e) => { | |
console.error('[FAILED]', e.response ? e.response.data : e.message) | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment