Commit 4abef2ef authored by Bitcoin Please's avatar Bitcoin Please
Browse files

Added fullfillment generator to store.

parent 256124d2
......@@ -5,6 +5,7 @@
import getAsset from './campaigns/getters/getAsset'
import getCampaign from './campaigns/getters/getCampaign'
import getCampaigns from './campaigns/getters/getCampaigns'
import getFullfillment from './campaigns/getters/getFullfillment'
/* Import modules (actions). */
import addAssurance from './campaigns/actions/addAssurance'
......@@ -31,6 +32,7 @@ const getters = {
getAsset,
getCampaign,
getCampaigns,
getFullfillment,
}
/* Actions. */
......
/* Import modules. */
const Nito = require('nitojs')
const DUST_LIMIT = 546
const MAX_LIMIT = 2099999997690000
/**
* Add Output
*
* Adds an output to the assurance contract.
*/
const _addOutput = (_outputs, _satoshis, _address) => {
// Check if the provided address is properly encoded.
if (!Nito.Address.isCashAddress(_address)) {
throw `Cannot add output, provided address '${_address}' does not use the valid CashAddr encoding.`
}
// Check if the provided satoshis is of the correct type.
if (isNaN(_satoshis)) {
throw `Cannot add output, provided satoshis '${_satoshis}' is not a number.`
}
// Check if the provided satoshis is an integer.
if (!Number.isInteger(_satoshis)) {
throw `Cannot add output, provided satoshis '${_satoshis}' is not an integer.`
}
// Check if the provided satoshis is a positive number.
if (_satoshis < 0) {
throw `Cannot add output, provided satoshis '${_satoshis}' is negative.`
}
// Check if the provided satoshis is large enough to be accepted.
if (_satoshis < DUST_LIMIT) {
throw `Cannot add output, provided satoshis '${_satoshis}' is smaller than the dust limit.`
}
// Check if the provided satoshis is too large to be accepted.
if (_satoshis > MAX_LIMIT) {
throw `Cannot add output, provided satoshis '${_satoshis}' is larger than the max limit.`
}
/* Set value. */
const value = Nito.Utils.encodeNumber(_satoshis)
/* Derive the locking script from the address. */
const locking_script = Buffer.from(
Nito.Address.toPubKeyHash(_address), 'hex')
/* Structure the output. */
const output = {
value,
locking_script,
}
/* Add the output to assurance contract. */
_outputs.push(output)
}
/**
* Serialize Input
*
* Creates a serialized input part to be used in a raw transaction.
*/
const _serializeInput = (
_previousTransactionHash,
_previousOutputIndex,
_unlockScript,
_sequenceNumber
) => {
/* Calculate unlock script length. */
const unlockScriptLength = Nito.Utils.varInt(_unlockScript.byteLength)
/* Return the serialized input structure, as a buffer. */
return Buffer.concat([
_previousTransactionHash,
_previousOutputIndex,
unlockScriptLength,
_unlockScript,
_sequenceNumber,
])
}
/**
* Serialize Outputs
*/
const _serializeOutputs = (_outputs) => {
/* Initialize output buffers. */
const outputBuffers = []
/* Handle all outputs. */
for (const currentOutput in _outputs) {
const output = _outputs[currentOutput]
// Create a lockscript length statement.
const lockscriptLength = Nito.Utils
.varInt(output.locking_script.byteLength)
// Return the serialized output.
outputBuffers.push(
Buffer.concat([
output.value,
lockscriptLength,
output.locking_script
])
)
}
/* Return output buffers. */
return Buffer.concat(outputBuffers)
}
/**
* Serialize Pledges
*/
const _serializePledges = (_pledges) => {
/* Initialize pledge buffers. */
const pledgeBuffers = []
/* Handle all pledges. */
_pledges.forEach(_pledge => {
/* Initialize sequence number. */
const sequenceNumber = Buffer.alloc(4)
/* Set sequence number. */
sequenceNumber.writeUInt32LE(_pledge.sequenceNumber)
/* Set previous transaction hash. */
const previousTransactionHash = Nito.Utils
.reverseBuffer(Buffer.from(_pledge.previousTransactionHash, 'hex'))
/* Initialize output index. */
const outputIndex = Buffer.alloc(4)
/* Set output index. */
outputIndex.writeUInt32LE(_pledge.previousOutputIndex)
/* Add input to buffers. */
pledgeBuffers.push(
/* Serialize input. */
_serializeInput(
previousTransactionHash,
outputIndex,
Buffer.from(_pledge.unlockScript, 'hex'),
sequenceNumber
)
)
})
/* Return pledge buffers. */
return Buffer.concat(pledgeBuffers)
}
/**
* Get Fullfillment
*
* Assembles all currently known commitments into a transaction.
*/
const getFullfillment = () => (_campaign) => {
// console.log('FULLFILLMENT (campaign):', _campaign)
/* Set pledges. */
const pledges = _campaign.assurance.pledges.filter(pledge => !pledge.isSpent)
// console.log('FULLFILLMENT (pledges):', pledges)
/* Set recipients. */
const recipients = _campaign.assurance.recipients
// console.log('FULLFILLMENT (recipients):', recipients)
// Create a buffered version statement.
const version = Buffer.from('02000000', 'hex')
// Create the input counter and input data buffers.
const inputCount = Nito.Utils.varInt(pledges.length)
/* Generate inputs. */
const inputs = _serializePledges(pledges)
// console.log('FULLFILLMENT (inputs):', inputs)
/* Initialize outputs. */
const outputs = []
// Create the output counter and output data buffer.
const outputCount = Nito.Utils
.varInt(Object.keys(recipients).length)
/* Handle all recipients. */
recipients.forEach(_recipient => {
_addOutput(
outputs,
_recipient.satoshis,
_recipient.address
)
})
// console.log('FULLFILLMENT (outputs):', outputs)
// console.log('FULLFILLMENT (_serializeOutputs):', _serializeOutputs(outputs))
// Create a buffered disable locktime statement.
const locktime = Buffer.from('00000000', 'hex')
/* Return the assembled transaction. */
return Buffer.concat([
version,
inputCount,
inputs,
outputCount,
_serializeOutputs(outputs),
locktime,
])
}
/* Export module. */
export default getFullfillment
......@@ -181,6 +181,10 @@ export default {
'getHelp',
]),
...mapGetters('campaigns', [
'getFullfillment',
]),
...mapGetters('wallet', [
'getAddress',
]),
......@@ -365,11 +369,22 @@ export default {
}, 10)
},
broadcast() {
async broadcast() {
console.log('STARTED BROADCASTING...')
const pledges = this.campaign.assurance.pledges.filter(pledge => !pledge.isSpent)
console.log('BROADCAST (pledges):', pledges)
try {
// Assemble pledges into transaction
const rawTransaction = this.getFullfillment(this.campaign)
console.log('RAW TRANSACTION', rawTransaction.toString('hex'))
const response = await Nito.Transaction
.sendRawTransaction(rawTransaction.toString('hex'))
.catch(err => console.error(err))
console.log('BROADCAST RESPONSE', response)
} catch (err) {
console.error(err)
}
},
/**
......
......@@ -10,7 +10,7 @@
<th class="text-center">Amount (USD)</th>
<th class="text-right">Time</th>
</tr>
<tr v-for="pledge of pledges" :key="pledge.previousTransactionHash">
<tr v-for="pledge of pledges" :key="pledge.previousTransactionHash + ':' + pledge.previousOutputIndex">
<td>{{pledge.alias}}</td>
<td class="text-center">{{pledge.comment}}</td>
<td class="text-center">{{formatAmount(pledge.satoshis)}}</td>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment