-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit d9dedf2
Showing
5 changed files
with
263 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
.idea/* | ||
|
||
node_modules/* | ||
|
||
bundle*.js | ||
.babel* | ||
|
||
.DS_Store* | ||
.DS_Store* |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
# Create BTCR DID | ||
|
||
This is a prototype-only script to create BTCR DIDs. | ||
|
||
|
||
## Install | ||
``` | ||
git clone [email protected]:WebOfTrustInfo/btcr-did-tools-js.git | ||
npm install | ||
``` | ||
|
||
## Preparation | ||
|
||
We recommend starting in testnet mode. You will need testnet addresses for the input address and the change address. | ||
|
||
|
||
### How to generate testnet addresses | ||
If you don't have a testnet address yet, and don't know how to create one, you can start with this client-side address generator: [https://www.bitaddress.org/?testnet=true](https://www.bitaddress.org/?testnet=true). | ||
|
||
As this is a client-side address generator, and will be passing private keys, go ahead and disconnect your internet connection. Even though this is testnet mode, it's a good practice to start following. | ||
|
||
Once you've disconnected from the internet and generated a testnet address, record the Bitcoin address (what you can share with the public) and the Private Key (always keep this private). The private key is in Wallet Import Format (WIF). | ||
|
||
 | ||
|
||
|
||
### How to get testnet funds | ||
|
||
Lastly, you'll need some funds in your input (funding) address before creating the Bitcoin testnet transaction in the following steps. | ||
|
||
To get some testnet funds, search for a testnet faucet and send to your input address. | ||
|
||
Be sure to hold onto your private keys. Even in testnet mode, you'll want to send your testnet coins back to the faucet provider when you are finished. This tool only uses a small amount of money, and many testnet faucets will send you much more than you need. | ||
|
||
|
||
## Ensure your private key WIF is available as an environment variable | ||
|
||
``` | ||
export WIF=<privateKeyWif> | ||
``` | ||
|
||
## Create BTCR DID with DDO/1 ref | ||
|
||
``` | ||
node createBtcrDid.js -i <inputAddress> -c <changeAddress> -d <link-to-ddo.jsonld> | ||
``` | ||
|
||
## Create BTCR DID without DDO/1 ref | ||
|
||
``` | ||
node createBtcrDid.js -i <inputAddress> -c <changeAddress> | ||
``` | ||
|
||
## Usage | ||
|
||
The default node is testnet; call `--help` for more options | ||
|
||
``` | ||
node createBtcrDid.js --help | ||
``` |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
var bitcoin = require('bitcoinjs-lib'); | ||
var program = require('commander'); | ||
var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest; | ||
|
||
|
||
const MAINNET_BLOCKR_IO = "https://btc.blockr.io/api/v1"; | ||
const TESTNET_BLOCKR_IO = "https://tbtc.blockr.io/api/v1"; | ||
const SATOSHIS_PER_BTC = 100000000; | ||
|
||
|
||
let request = obj => { | ||
return new Promise((resolve, reject) => { | ||
let request = new XMLHttpRequest(); | ||
|
||
request.addEventListener('load', () => { | ||
if (request.status >= 200 && request.status < 300) { | ||
resolve(request.responseText); | ||
} else { | ||
reject(new Error(request.responseText)); | ||
} | ||
}); | ||
request.addEventListener('error', () => { | ||
console.error(request.status); | ||
reject(new Error(request.status)); | ||
}); | ||
|
||
request.open(obj.method || "GET", obj.url); | ||
request.responseType = "json"; | ||
if (obj.body !== null) { | ||
request.send(JSON.stringify(obj.body)); | ||
} else { | ||
request.send(); | ||
} | ||
}); | ||
}; | ||
|
||
|
||
class UnspentOut { | ||
/** | ||
* | ||
* @param address | ||
* @param txid | ||
* @param amount in BTC | ||
* @param numConfirmations | ||
* @param script | ||
*/ | ||
constructor(address, txid, amount, numConfirmations, script) { | ||
this.address = address; | ||
this.txid = txid; | ||
this.amount = amount; | ||
this.numConfirmations = numConfirmations; | ||
this.script = script; | ||
} | ||
} | ||
|
||
|
||
class BlockrIOBroadcaster { | ||
constructor(baseUrl) { | ||
this.baseUrl = baseUrl; | ||
} | ||
|
||
getUnspentOutputs(address) { | ||
let url = this.baseUrl + "/address/unspent/" + address; | ||
let obj = { | ||
"url": url | ||
}; | ||
return request(obj) | ||
.then(result => { | ||
let resultJson = JSON.parse(result); | ||
if (resultJson.data.unspent == null || resultJson.data.unspent.length == 0) { | ||
throw Error("no unspent outputs for address " + address); | ||
} | ||
let firstUnspent = resultJson.data.unspent[0]; | ||
return new UnspentOut(address, | ||
firstUnspent.tx, | ||
firstUnspent.amount, | ||
firstUnspent.confirmations, | ||
firstUnspent.script); | ||
}, error => { | ||
console.error(error); | ||
throw error; | ||
}); | ||
} | ||
|
||
broadcast(hextx) { | ||
let url = this.baseUrl + '/tx/push'; | ||
let obj = { | ||
"url": url, | ||
"method": "POST", | ||
"body": {"hex": hextx} | ||
}; | ||
return request(obj) | ||
.then(result => { | ||
return result; | ||
}, error => { | ||
console.error(error); | ||
throw error; | ||
}); | ||
} | ||
} | ||
|
||
|
||
var createDidTx = function (network, wif, inputTxid, outputAddress, ddo1Ref, changeAmount) { | ||
let tx = new bitcoin.TransactionBuilder(network); | ||
tx.addInput(inputTxid, 0); | ||
tx.addOutput(outputAddress, changeAmount); | ||
|
||
if (ddo1Ref !== null) { | ||
let data = new Buffer(ddo1Ref); | ||
ret = bitcoin.script.compile( | ||
[ | ||
bitcoin.opcodes.OP_RETURN, | ||
data | ||
]); | ||
tx.addOutput(ret, 0); | ||
} | ||
key = bitcoin.ECPair.fromWIF(wif, network); | ||
tx.sign(0, key); | ||
return tx.build().toHex(); | ||
} | ||
|
||
|
||
|
||
var inputAddress = null; | ||
var changeAddress = null; | ||
var ddo1Ref = null; | ||
var fee = 0; | ||
var chain = null; | ||
|
||
|
||
program | ||
.version('1.0.0') | ||
.usage('[options]') | ||
.option('-i, --inputAddress <inputAddress>', 'input (funding) address; required') | ||
.option('-c, --changeAddress <changeAddress>', 'change address; required') | ||
.option('-n, --network <network>', 'testnet or mainnet; default is testnet', 'testnet') | ||
.option('-d, --ddo1Ref <ddo1Ref>', 'DDO/1 reference; will be added to the OP_RETURN field. Can be null') | ||
.option('-f, --fee <fee>', 'Transaction fee in BTC. Default is 0.001 BTC', 0.001); | ||
|
||
program.parse(process.argv); | ||
|
||
inputAddress = program.inputAddress; | ||
changeAddress = program.changeAddress; | ||
ddo1Ref = program.ddo1Ref; | ||
fee = program.fee; | ||
chain = program.network === "mainnet" ? bitcoin.networks.mainnet : bitcoin.networks.testnet; | ||
|
||
if (inputAddress === null || changeAddress === null) { | ||
program.help(); | ||
process.exit(1); | ||
} | ||
|
||
let baseUrl = chain === bitcoin.networks.bitcoin ? MAINNET_BLOCKR_IO : TESTNET_BLOCKR_IO; | ||
let connector = new BlockrIOBroadcaster(baseUrl); | ||
|
||
let wif = process.env.WIF; | ||
|
||
connector.getUnspentOutputs(inputAddress) | ||
.then(unspentOutput => { | ||
let change = unspentOutput.amount - fee; // BTC | ||
let changeSatoshi = change * SATOSHIS_PER_BTC; // SATOSHI | ||
let signedHexTx = createDidTx(chain, wif, unspentOutput.txid, changeAddress, ddo1Ref, changeSatoshi); | ||
connector.broadcast(signedHexTx) | ||
.then(result => { | ||
console.log(result); | ||
return result; | ||
}, error => { | ||
console.error(error); | ||
throw error; | ||
}); | ||
|
||
}, error => { | ||
console.error(error); | ||
throw error; | ||
}); | ||
|
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
{ | ||
"name": "btcr-did-js", | ||
"version": "1.0.0", | ||
"description": "", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "npm run test" | ||
}, | ||
"author": "Kim Hamilton Duffy", | ||
"license": "MIT", | ||
"dependencies": { | ||
"bitcoinjs-lib": "^3.1.0", | ||
"commander": "^2.11.0", | ||
"xmlhttprequest": "^1.8.0" | ||
} | ||
} |