-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #6 from jeton-tech/price
threshold module and example
- Loading branch information
Showing
10 changed files
with
512 additions
and
6 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,116 @@ | ||
const jeton = require('../index') | ||
const PrivateKey = jeton.PrivateKey | ||
const ThresholdMessage = jeton.threshold.Message | ||
const OutputScript = jeton.threshold.OutputScript | ||
const Transaction = jeton.Transaction | ||
const Signature = jeton.Signature | ||
|
||
// Create keypairs for 2 players and an oracle | ||
const priv1 = new PrivateKey("KzwmMwHjbmRRdtwVUowKpYmpnJmMaVyGTwYLmh2qmiWcqgd7W9fG") | ||
const pub1 = priv1.toPublicKey() | ||
const priv2 = new PrivateKey("KzyhHmmxwFbv2Mo8bQsJQwXhrCgAtjsCmuqBBmGZrcjfTn1Xvzw1") | ||
const pub2 = priv2.toPublicKey() | ||
|
||
var utxoForPub2 = new Transaction.UnspentOutput({ | ||
txid: | ||
'b2b671f0cb3d7710b5d8a8420fff14b18173de876da710438dafa0ae6e8f5357', | ||
vout: 1, | ||
satoshis: 10200, | ||
scriptPubKey: '76a9149383fa6588a176c2592cb2f4008d779293246adb88ac' | ||
}) | ||
|
||
var utxoForPub1 = new Transaction.UnspentOutput({ | ||
txid: | ||
'ee874221a431cf09d3373c4b9ffbb1e8fe80526d4304695e2f97541fc084c8f4', | ||
vout: 1, | ||
satoshis: 10200, | ||
scriptPubKey: '76a914b011100d12d0537232692b3c113be5a8f505395588ac' | ||
}) | ||
|
||
// Create array of UTXO arrays | ||
var splitUtxos = [utxoForPub1, utxoForPub2] | ||
|
||
const oraclePriv = new PrivateKey('L5FDo3MEb2QNs2aQJ5DVGSDE5eBzVsgZny15Ri649RjysWAeLkTs') | ||
const oraclePub = oraclePriv.toPublicKey(); | ||
console.log('user 1 pubkey', pub1.toString()) | ||
console.log('user 2 pubkey', pub2.toString()) | ||
console.log('oracle pubkey', oraclePub.toString()) | ||
|
||
const blockheight = 660211 | ||
const price = 220.2098 | ||
|
||
// This is the ASM for the redeem script if done in CashScript | ||
// 0556 f2120a 029207e74ee73342f9af30859c03f684da444344d957a949c768316519f9df6a36 02c3e42dd2a3806f1bc9a9f32c3a97b872ed03ce8a779242b8bf2dba636ce655b0 OP_6 OP_PICK OP_4 OP_SPLIT OP_DROP OP_BIN2NUM OP_7 OP_PICK OP_4 OP_SPLIT OP_NIP OP_BIN2NUM OP_OVER OP_5 OP_ROLL OP_GREATERTHANOREQUAL OP_VERIFY OP_SWAP OP_CHECKLOCKTIMEVERIFY OP_DROP OP_3 OP_ROLL OP_GREATERTHANOREQUAL OP_VERIFY OP_3 OP_ROLL OP_4 OP_ROLL OP_3 OP_ROLL OP_CHECKDATASIGVERIFY OP_CHECKSIG | ||
|
||
let message = new ThresholdMessage(blockheight, price).message | ||
console.log('message', message) | ||
let oracleSig = Signature.signCDS(message, oraclePriv) | ||
// console.log('sig DER', oracleSig.toDER()) | ||
let verify = ThresholdMessage.verifySignature(message, oracleSig, oraclePub) | ||
// console.log('signature verified?', verify) | ||
|
||
// Create the output script | ||
var outputScriptData = { | ||
threshold: 218, | ||
blockheight: blockheight, | ||
oraclePubKey: oraclePub, | ||
parties: { | ||
gt: {pubKey: pub1}, | ||
lte: {pubKey: pub2} | ||
} | ||
} | ||
|
||
outScript = new OutputScript(outputScriptData) | ||
|
||
let outputScript = outScript.toScript() | ||
|
||
// console.log(outputScript) | ||
|
||
let outScriptHex = outScript.toScript().toHex() | ||
|
||
// console.log('destination P2SH', outScript.toAddress()) | ||
|
||
// Set miner fee and total amount to send (will be split between UTXOs from useUTXOs array) | ||
var splitUtxoMinerFee = 200 | ||
var amountToSend = 20000 | ||
|
||
var splitTxSendAmount = (amountToSend / splitUtxos.length) | ||
|
||
// Create two separate transactions from players 2 and 3 to fund the escrow | ||
var sighash = (Signature.SIGHASH_ALL | Signature.SIGHASH_FORKID | Signature.SIGHASH_ANYONECANPAY) | ||
var txArray = [] | ||
for (let i = 0; i < splitUtxos.length; i++) { | ||
txArray[i] = new Transaction() | ||
.from(splitUtxos[i]) // Feed information about what unspent outputs one can use | ||
.toP2SH(outScript, amountToSend) | ||
.sign([priv1, priv2], sighash) // Signs all the inputs it can | ||
} | ||
|
||
// Combine the transactions by merging the inputs | ||
var fundTx = Transaction.mergeTransactionInputs(txArray) | ||
|
||
// var itx = new Transaction(fundTx.toString()) | ||
|
||
// console.log('fundTx', itx.toObject()) | ||
|
||
// Now spend the escrow transaction... | ||
|
||
var escrowUtxo = Transaction.utxoFromTxOutput(fundTx, 0) | ||
|
||
// Make Transaction from escrow UTXO | ||
sighash = (Signature.SIGHASH_ALL | Signature.SIGHASH_FORKID) | ||
|
||
var spendTx = new Transaction() | ||
.from(escrowUtxo) | ||
.to(priv1.toAddress(), 19000) | ||
.lockUntilBlockHeight(660211) // Must be after the blockheight in the script | ||
|
||
//console.log(spendTx.toObject()) | ||
|
||
// Sign CDS input at index 0 as player 2 | ||
spendTx.signThreshold(0, priv1, message, oracleSig, outScript.toScript(), sighash) | ||
|
||
// console.log(spendTx.toObject()) | ||
console.log('estimated size', spendTx._estimateSize()) | ||
console.log('verify tx full sig', spendTx.verify()) | ||
console.log('jeton signature verified?', spendTx.verifyScriptSig(0)) |
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
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
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,50 @@ | ||
const bitcore = require('bitcore-lib-cash') | ||
const Hash = bitcore.crypto.Hash | ||
const Script = bitcore.Script | ||
const PublicKey = bitcore.PublicKey | ||
|
||
|
||
/** | ||
* Instantiate an object to create escrow scriptSig | ||
* | ||
* @param {object} data - The encoded data in various formats | ||
* @param {Signature} data.oracleSig | ||
* @param {Buffer} data.message | ||
* @param {Script} data.winnerScript - a P2PKH scriptSig for the transaction signed by escrow beneficiary | ||
* @param {Script} data.outputScript - The original (non-P2SH) scriptPubKey for this input | ||
* | ||
* @constructor | ||
*/ | ||
var InputScript = function (data) { | ||
|
||
this.oracleSig = data.oracleSig | ||
this.message = data.message | ||
this.winnerScript = data.winnerScript | ||
this.outputScript = data.outputScript | ||
} | ||
|
||
|
||
/** | ||
* @returns {Script} | ||
*/ | ||
InputScript.prototype.toScript = function () { | ||
let outputBuf = this.outputScript.toBuffer() | ||
let inScript = Script() | ||
.add(this.winnerScript) | ||
.add(this.oracleSig.toBuffer()) | ||
.add(this.message) | ||
.add(outputBuf) | ||
|
||
return inScript | ||
} | ||
|
||
|
||
/** | ||
* @returns {Buffer} | ||
*/ | ||
InputScript.prototype.toBuffer = function () { | ||
let outScript = this.toScript() | ||
return outScript.toBuffer() | ||
} | ||
|
||
module.exports = InputScript |
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,47 @@ | ||
const bitcore = require('bitcore-lib-cash') | ||
const Address = bitcore.Address | ||
const Hash = bitcore.crypto.Hash | ||
const ECDSA = bitcore.crypto.ECDSA | ||
const Signature = bitcore.crypto.Signature | ||
const Script = bitcore.Script | ||
const PrivateKey = bitcore.PrivateKey | ||
const PublicKey = bitcore.PublicKey | ||
const ScriptNumber = require('./ScriptNumber') | ||
|
||
var Message = function (blockHeight, thresholdValue) { | ||
|
||
this.blockHeight = blockHeight | ||
this.threshold = Math.ceil(thresholdValue) | ||
this.message = this.createMessage() | ||
} | ||
|
||
/** | ||
* Encode a blockHeight and threshold amount into a byte sequence of 8 bytes (4 bytes per value) | ||
* This is compatible with the CashScript PriceOracle.ts | ||
* https://github.com/Bitcoin-com/cashscript/blob/master/examples/PriceOracle.ts | ||
* | ||
* | ||
*/ | ||
Message.prototype.createMessage = function () { | ||
const lhs = Buffer.alloc(4, 0); | ||
const rhs = Buffer.alloc(4, 0); | ||
ScriptNumber.encode(this.blockHeight).copy(lhs); | ||
ScriptNumber.encode(this.threshold).copy(rhs); | ||
console.log('decoded price', ScriptNumber.decode(rhs, 4, false)) | ||
console.log('decoded threshold', ScriptNumber.decode(lhs, 4, false)) | ||
return Buffer.concat([lhs, rhs]); | ||
} | ||
|
||
Message.signMessage = function(message, privkey){ | ||
return new ECDSA().set({ | ||
hashbuf: Hash.sha256(message), | ||
privkey: privkey | ||
}).signRandomK().sig; | ||
} | ||
|
||
Message.verifySignature = function(message, sig, pubkey) { | ||
let msgHash = Hash.sha256(message) | ||
return ECDSA.verify(msgHash, sig, pubkey) | ||
} | ||
|
||
module.exports = Message |
Oops, something went wrong.