@trivechain/triveasset-protocol
Version:
TriveAsset Protocol provides the definition, encode and decode functions that recognize a TriveAsset Encoding
741 lines (722 loc) • 17.1 kB
JavaScript
/* eslint-env mocha */
const getAssetsOutputs = require('../src/getAssetsOutputs')
const assert = require('assert')
const issuanceTx = {
vin: [
{
assets: [],
},
{
assets: [],
},
],
vout: [{}, {}, {}],
ccdata: [
{
payments: [
{
input: 0,
amount: 10,
output: 0,
range: false,
percent: false,
},
{
input: 0,
amount: 6,
output: 0,
range: false,
percent: false,
},
{
input: 0,
amount: 7,
output: 1,
range: false,
percent: false,
},
],
protocol: 0x5441,
version: 2,
type: 'issuance',
lockStatus: false,
aggregationPolicy: 'dispersed',
amount: 25,
multiSig: [],
},
],
}
const transferTx = {
vin: [
{
assets: [
{
assetId: 'A',
amount: 10,
issueTxid: 'aaa',
divisibility: 0,
lockStatus: false,
aggregationPolicy: 'aggregatable',
},
{
assetId: 'A',
amount: 5,
issueTxid: 'aaa',
divisibility: 0,
lockStatus: false,
aggregationPolicy: 'aggregatable',
},
],
},
{
assets: [
{
assetId: 'A',
amount: 6,
issueTxid: 'aaa',
divisibility: 0,
lockStatus: false,
aggregationPolicy: 'aggregatable',
},
],
},
],
vout: [{}, {}, {}],
ccdata: [
{
payments: [
{
input: 0,
amount: 10,
output: 0,
range: false,
percent: false,
},
{
input: 0,
amount: 5,
output: 0,
range: false,
percent: false,
},
{
input: 1,
amount: 4,
output: 2,
range: false,
percent: false,
},
],
protocol: 0x5441,
version: 1,
type: 'transfer',
multiSig: [],
},
],
}
it('Issuance - should transfer the correct amounts, split according to payments', function (done) {
const res = getAssetsOutputs(issuanceTx)
assert.equal(Array.isArray(res), true)
assert.equal(res.length, 3)
assert.equal(Array.isArray(res[0]), true)
assert.equal(res[0].length, 2)
assert.equal(res[0][0].amount, 10)
assert.equal(res[0][1].amount, 6)
assert.equal(Array.isArray(res[1]), true)
assert.equal(res[1].length, 1)
assert.equal(res[1][0].amount, 7)
assert.equal(Array.isArray(res[2]), true)
assert.equal(res[2].length, 1)
assert.equal(res[2][0].amount, 2)
done()
})
it('Issuance - should transfer entire amount to last output when overflow in total amount in payments', function (done) {
issuanceTx.ccdata[0].payments = [
{
input: 0,
amount: 100,
output: 0,
range: false,
percent: false,
},
]
const res = getAssetsOutputs(issuanceTx)
assert.equal(Array.isArray(res), true)
assert.equal(res.length, 3)
assert.equal(res[2].length, 1)
assert.equal(res[2][0].amount, 25)
assert.equal(issuanceTx.overflow, true)
done()
})
it('Issuance - should transfer entire amount to last output there is overflow in total amount, even when first payments can be satisfied', function (done) {
issuanceTx.ccdata[0].payments = [
{
input: 0,
amount: 10,
output: 0,
range: false,
percent: false,
},
{
input: 0,
amount: 90,
output: 0,
range: false,
percent: false,
},
]
const res = getAssetsOutputs(issuanceTx)
assert.equal(Array.isArray(res), true)
assert.equal(res.length, 3)
assert.equal(res[0], null)
assert.equal(res[1], null)
assert.equal(res[2].length, 1)
assert.equal(res[2][0].amount, 25)
done()
})
it('Transfer - should transfer the correct amounts, split according to payments (even when asset is aggregatable)', function (done) {
const res = getAssetsOutputs(transferTx)
assert.equal(Array.isArray(res), true)
assert.equal(res.length, 3)
assert.equal(res[0].length, 2)
assert.equal(res[0][0].amount, 10)
assert.equal(res[0][1].amount, 5)
assert.equal(res[2].length, 2)
assert.equal(res[2][0].amount, 4)
assert.equal(res[2][1].amount, 2)
done()
})
it('Transfer - should transfer the entire amount to last output, when there is an overflow in total amount. If assets are aggregatable - should aggregate them together.', function (done) {
transferTx.ccdata[0].payments = [
{
input: 0,
amount: 100,
output: 0,
range: false,
percent: false,
},
]
const res = getAssetsOutputs(transferTx)
assert.equal(Array.isArray(res), true)
assert.equal(res.length, 3)
assert.equal(Array.isArray(res[2]), true)
assert.equal(res[2].length, 1)
assert.equal(res[2][0].amount, 21)
assert.equal(issuanceTx.overflow, true)
done()
})
it('Transfer - should transfer correct amounts, when there is an overflow to the same aggregatable assetId asset with a different input', function (done) {
transferTx.ccdata[0].payments = [
{
input: 0,
amount: 10,
output: 0,
range: false,
percent: false,
},
{
input: 0,
amount: 10, // that's an overflow, but to the same aggregatable asset-id within the next input
output: 2,
range: false,
percent: false,
},
]
const res = getAssetsOutputs(transferTx)
assert.equal(Array.isArray(res), true)
assert.equal(res.length, 3)
assert.equal(Array.isArray(res[0]), true)
assert.equal(res[0].length, 1)
assert.equal(res[0][0].amount, 10)
assert.equal(Array.isArray(res[2]), true)
assert.equal(res[2].length, 2)
assert.equal(res[2][0].amount, 10) // aggregate
assert.equal(res[2][1].amount, 1) // change - we keep it separated because we respect the payment
done()
})
it('Transfer - should transfer correct amounts, when there is an overflow to the same aggregatable assetId asset within the same input', function (done) {
transferTx.ccdata[0].payments = [
{
input: 0,
amount: 13, // that's an overflow, but to the same aggregatable asset-id within the same input
output: 0,
range: false,
percent: false,
},
{
input: 0,
amount: 2,
output: 2,
range: false,
percent: false,
},
{
input: 1,
amount: 5,
output: 2,
range: false,
percent: false,
},
]
const res = getAssetsOutputs(transferTx)
assert.equal(Array.isArray(res), true)
assert.equal(res.length, 3)
assert.equal(Array.isArray(res[0]), true)
assert.equal(res[0].length, 1)
assert.equal(res[0][0].amount, 13)
assert.equal(Array.isArray(res[2]), true)
assert.equal(res[2].length, 3)
assert.equal(res[2][0].amount, 2)
assert.equal(res[2][1].amount, 5)
assert.equal(res[2][2].amount, 1) // change - we keep it separated because we respect the payment
done()
})
it('Transfer - should transfer the entire amount to last output, when there is an overflow in total amount. If assets are NOT aggregatable - should keep them separated.', function (done) {
transferTx.ccdata[0].payments = [
{
input: 0,
amount: 100,
output: 0,
range: false,
percent: false,
},
]
transferTx.vin.forEach(function (vin) {
vin.assets.forEach(function (asset) {
asset.aggregationPolicy = 'dispersed'
})
})
const res = getAssetsOutputs(transferTx)
assert.equal(Array.isArray(res), true)
assert.equal(res.length, 3)
assert.equal(Array.isArray(res[2]), true)
assert.equal(res[2].length, 3)
assert.equal(res[2][0].amount, 10)
assert.equal(res[2][1].amount, 5)
assert.equal(res[2][2].amount, 6)
done()
})
it('Transfer - should transfer the entire amount to last output, when there is an overflow to another asset which is not aggregatable with the previous asset.', function (done) {
transferTx.ccdata[0].payments = [
{
input: 0,
amount: 13, // that's an overflow
output: 0,
range: false,
percent: false,
},
{
input: 0,
amount: 2,
output: 2,
range: false,
percent: false,
},
{
input: 1,
amount: 6,
output: 2,
range: false,
percent: false,
},
]
const res = getAssetsOutputs(transferTx)
assert.equal(transferTx.overflow, true)
assert.equal(Array.isArray(res), true)
assert.equal(res.length, 3)
assert.equal(Array.isArray(res[2]), true)
assert.equal(res[2].length, 3)
assert.equal(res[2][0].amount, 10)
assert.equal(res[2][1].amount, 5)
assert.equal(res[2][2].amount, 6)
done()
})
it('Transfer - should not have overflow with payment with amount 0', function (done) {
transferTx.ccdata[0].payments = [
{
input: 0,
amount: 10,
output: 0,
range: false,
percent: false,
},
{
input: 0,
amount: 5,
output: 2,
range: false,
percent: false,
},
{
input: 1,
amount: 6,
output: 2,
range: false,
percent: false,
},
{
input: 1,
amount: 0,
output: 2,
range: false,
percent: false,
},
]
const res = getAssetsOutputs(transferTx)
assert.equal(transferTx.overflow, false)
assert.equal(Array.isArray(res), true)
assert.equal(res.length, 3)
assert.equal(Array.isArray(res[0]), true)
assert.equal(res[0].length, 1)
assert.equal(res[0][0].amount, 10)
assert.equal(Array.isArray(res[2]), true)
assert.equal(res[2].length, 2)
assert.equal(res[2][0].amount, 5)
assert.equal(res[2][1].amount, 6)
done()
})
it('Transfer - should transfer entire amount to last output when there is a payment to a non existing output', function (done) {
transferTx.ccdata[0].payments = [
{
input: 0,
amount: 10,
output: 0,
range: false,
percent: false,
},
{
input: 0,
amount: 5,
output: 2,
range: false,
percent: false,
},
{
input: 1,
amount: 6,
output: 2,
range: false,
percent: false,
},
{
input: 1,
amount: 0,
output: 3,
range: false,
percent: false,
},
]
const res = getAssetsOutputs(transferTx)
assert.equal(transferTx.overflow, true)
assert.equal(Array.isArray(res), true)
assert.equal(res.length, 3)
assert.equal(Array.isArray(res[2]), true)
assert.equal(res[2].length, 3)
assert.equal(res[2][0].amount, 10)
assert.equal(res[2][1].amount, 5)
assert.equal(res[2][2].amount, 6)
done()
})
it('Transfer - should transfer remaining amounts to last output', function (done) {
const tx = {
vin: [
{
assets: [
{
assetId: 'A',
amount: 10,
issueTxid: 'aaa',
divisibility: 0,
lockStatus: false,
aggregationPolicy: 'aggregatable',
},
],
},
{
assets: [
{
assetId: 'B',
amount: 5,
issueTxid: 'bbb',
divisibility: 0,
lockStatus: false,
aggregationPolicy: 'aggregatable',
},
],
},
{
assets: [
{
assetId: 'C',
amount: 6,
issueTxid: 'ccc',
divisibility: 0,
lockStatus: false,
aggregationPolicy: 'aggregatable',
},
],
},
],
vout: [{}, {}, {}],
ccdata: [
{
payments: [
{
input: 0,
amount: 0,
output: 0,
range: false,
percent: false,
},
{
input: 1,
amount: 0,
output: 0,
range: false,
percent: false,
},
{
input: 2,
amount: 4,
output: 0,
range: false,
percent: false,
},
],
protocol: 0x5441,
version: 1,
type: 'transfer',
multiSig: [],
},
],
}
const res = getAssetsOutputs(tx)
assert.equal(tx.overflow, false)
assert.equal(Array.isArray(res), true)
assert.equal(res.length, 3)
assert.equal(Array.isArray(res[0]), true)
assert.equal(res[0].length, 1)
assert.equal(res[0][0].amount, 4)
assert.equal(Array.isArray(res[2]), true)
assert.equal(res[2].length, 3)
assert.equal(res[2][0].amount, 10)
assert.equal(res[2][0].assetId, 'A')
assert.equal(res[2][1].amount, 5)
assert.equal(res[2][1].assetId, 'B')
assert.equal(res[2][2].amount, 2)
assert.equal(res[2][2].assetId, 'C')
done()
})
it('Burn - should transfer and burn assets', function (done) {
const burnTx = {
vin: [
{
assets: [
{
assetId: 'A',
amount: 6,
issueTxid: 'aaa',
divisibility: 0,
lockStatus: false,
aggregationPolicy: 'aggregatable',
},
],
},
{
assets: [
{
assetId: 'B',
amount: 6,
issueTxid: 'bbb',
divisibility: 0,
lockStatus: false,
aggregationPolicy: 'aggregatable',
},
],
},
{
assets: [
{
assetId: 'C',
amount: 6,
issueTxid: 'ccc',
divisibility: 0,
lockStatus: false,
aggregationPolicy: 'aggregatable',
},
],
},
],
vout: [{}, {}, {}],
ccdata: [
{
payments: [
{
input: 0,
amount: 3,
output: 1,
range: false,
percent: false,
},
{
input: 0,
amount: 2,
percent: false,
burn: true,
},
{
input: 1,
amount: 3,
output: 0,
range: false,
percent: false,
},
{
input: 1,
amount: 2,
burn: true,
percent: false,
},
],
protocol: 0x5441,
version: 1,
type: 'burn',
multiSig: [],
},
],
}
const res = getAssetsOutputs(burnTx)
assert.deepEqual(res, [
[
{
assetId: 'B',
amount: 3,
issueTxid: 'bbb',
divisibility: 0,
lockStatus: false,
aggregationPolicy: 'aggregatable',
},
],
[
{
assetId: 'A',
amount: 3,
issueTxid: 'aaa',
divisibility: 0,
lockStatus: false,
aggregationPolicy: 'aggregatable',
},
],
[
{
assetId: 'A',
amount: 1,
issueTxid: 'aaa',
divisibility: 0,
lockStatus: false,
aggregationPolicy: 'aggregatable',
},
{
assetId: 'B',
amount: 1,
issueTxid: 'bbb',
divisibility: 0,
lockStatus: false,
aggregationPolicy: 'aggregatable',
},
{
assetId: 'C',
amount: 6,
issueTxid: 'ccc',
divisibility: 0,
lockStatus: false,
aggregationPolicy: 'aggregatable',
},
],
])
done()
})
it('Burn - should transfer all assets to last output when there is an overflow', function (done) {
const burnTx = {
vin: [
{
assets: [
{
assetId: 'A',
amount: 6,
issueTxid: 'aaa',
divisibility: 0,
lockStatus: false,
aggregationPolicy: 'aggregatable',
},
],
},
{
assets: [
{
assetId: 'B',
amount: 6,
issueTxid: 'bbb',
divisibility: 0,
lockStatus: false,
aggregationPolicy: 'aggregatable',
},
],
},
],
vout: [{}, {}, {}],
ccdata: [
{
payments: [
{
input: 0,
amount: 3,
output: 1,
range: false,
percent: false,
},
{
input: 0,
amount: 2,
percent: false,
burn: true,
},
{
input: 0,
amount: 2,
output: 0,
range: false,
percent: false,
},
],
protocol: 0x5441,
version: 1,
type: 'burn',
multiSig: [],
},
],
}
const res = getAssetsOutputs(burnTx)
assert.equal(burnTx.overflow, true)
assert.deepEqual(res[0], undefined)
assert.deepEqual(res[1], undefined)
assert.deepEqual(res[2], [
{
assetId: 'A',
amount: 6,
issueTxid: 'aaa',
divisibility: 0,
lockStatus: false,
aggregationPolicy: 'aggregatable',
},
{
assetId: 'B',
amount: 6,
issueTxid: 'bbb',
divisibility: 0,
lockStatus: false,
aggregationPolicy: 'aggregatable',
},
])
done()
})