commit
f4940ccd48
2 changed files with 83 additions and 29 deletions
|
@ -77,20 +77,21 @@ function Wallet(seed, network) {
|
|||
utxo.forEach(function(uo){
|
||||
validateUnspentOutput(uo)
|
||||
var o = unspentOutputToOutput(uo)
|
||||
outputs[o.receive] = o
|
||||
outputs[o.from] = o
|
||||
})
|
||||
|
||||
this.outputs = outputs
|
||||
}
|
||||
|
||||
function outputToUnspentOutput(output){
|
||||
var hashAndIndex = output.receive.split(":")
|
||||
var hashAndIndex = output.from.split(":")
|
||||
|
||||
return {
|
||||
hash: hashAndIndex[0],
|
||||
outputIndex: parseInt(hashAndIndex[1]),
|
||||
address: output.address,
|
||||
value: output.value
|
||||
value: output.value,
|
||||
pending: output.pending
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -98,7 +99,7 @@ function Wallet(seed, network) {
|
|||
var hash = o.hash
|
||||
var key = hash + ":" + o.outputIndex
|
||||
return {
|
||||
receive: key,
|
||||
from: key,
|
||||
address: o.address,
|
||||
value: o.value,
|
||||
pending: o.pending
|
||||
|
@ -158,7 +159,7 @@ function Wallet(seed, network) {
|
|||
var output = txid + ':' + i
|
||||
|
||||
me.outputs[output] = {
|
||||
receive: output,
|
||||
from: output,
|
||||
value: txOut.value,
|
||||
address: address,
|
||||
pending: isPending
|
||||
|
@ -174,7 +175,13 @@ function Wallet(seed, network) {
|
|||
|
||||
var output = txinId + ':' + txIn.index
|
||||
|
||||
if(me.outputs[output]) delete me.outputs[output]
|
||||
if (!(output in me.outputs)) return
|
||||
|
||||
if (isPending) {
|
||||
return me.outputs[output].pending = true
|
||||
}
|
||||
|
||||
delete me.outputs[output]
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -193,7 +200,7 @@ function Wallet(seed, network) {
|
|||
var utxo = utxos[i]
|
||||
addresses.push(utxo.address)
|
||||
|
||||
var outpoint = utxo.receive.split(':')
|
||||
var outpoint = utxo.from.split(':')
|
||||
tx.addInput(outpoint[0], parseInt(outpoint[1]))
|
||||
|
||||
var fee = fixedFee == undefined ? estimateFeePadChangeOutput(tx) : fixedFee
|
||||
|
@ -234,7 +241,7 @@ function Wallet(seed, network) {
|
|||
|
||||
function estimateFeePadChangeOutput(tx) {
|
||||
var tmpTx = tx.clone()
|
||||
tmpTx.addOutput(getChangeAddress(), 0)
|
||||
tmpTx.addOutput(getChangeAddress(), network.dustSoftThreshold || 0)
|
||||
|
||||
return network.estimateFee(tmpTx)
|
||||
}
|
||||
|
|
|
@ -175,7 +175,8 @@ describe('Wallet', function() {
|
|||
"hash":"6a4062273ac4f9ea4ffca52d9fd102b08f6c32faa0a4d1318e3a7b2e437bb9c7",
|
||||
"outputIndex": 0,
|
||||
"address" : "1AZpKpcfCzKDUeTFBQUL4MokQai3m3HMXv",
|
||||
"value": 20000
|
||||
"value": 20000,
|
||||
"pending": true
|
||||
}
|
||||
expectedOutputKey = expectedUtxo.hash + ":" + expectedUtxo.outputIndex
|
||||
})
|
||||
|
@ -183,9 +184,10 @@ describe('Wallet', function() {
|
|||
function addUtxoToOutput(utxo){
|
||||
var key = utxo.hash + ":" + utxo.outputIndex
|
||||
wallet.outputs[key] = {
|
||||
receive: key,
|
||||
from: key,
|
||||
address: utxo.address,
|
||||
value: utxo.value
|
||||
value: utxo.value,
|
||||
pending: utxo.pending
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -262,12 +264,35 @@ describe('Wallet', function() {
|
|||
})
|
||||
|
||||
describe("processPendingTx", function(){
|
||||
it("sets the pending flag on output", function(){
|
||||
it("incoming: sets the pending flag on output", function(){
|
||||
wallet.addresses = [addresses[0]]
|
||||
wallet.processPendingTx(tx)
|
||||
|
||||
verifyOutputAdded(0, true)
|
||||
})
|
||||
|
||||
describe("when tx ins outpoint contains a known txhash:i", function(){
|
||||
var spendTx
|
||||
beforeEach(function(){
|
||||
wallet.addresses = [addresses[0]]
|
||||
wallet.processConfirmedTx(tx)
|
||||
|
||||
spendTx = Transaction.fromHex(fixtureTx2Hex)
|
||||
})
|
||||
|
||||
it("outgoing: sets the pending flag on output instead of deleting it", function(){
|
||||
var txIn = spendTx.ins[0]
|
||||
var txInId = new Buffer(txIn.hash)
|
||||
Array.prototype.reverse.call(txInId)
|
||||
txInId = txInId.toString('hex')
|
||||
|
||||
var key = txInId + ':' + txIn.index
|
||||
assert(!wallet.outputs[key].pending)
|
||||
|
||||
wallet.processPendingTx(spendTx)
|
||||
assert(wallet.outputs[key].pending)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('processConfirmedTx', function(){
|
||||
|
@ -350,7 +375,7 @@ describe('Wallet', function() {
|
|||
var txOut = tx.outs[index]
|
||||
var key = tx.getId() + ":" + index
|
||||
var output = wallet.outputs[key]
|
||||
assert.equal(output.receive, key)
|
||||
assert.equal(output.from, key)
|
||||
assert.equal(output.value, txOut.value)
|
||||
assert.equal(output.pending, pending)
|
||||
|
||||
|
@ -395,25 +420,12 @@ describe('Wallet', function() {
|
|||
wallet.setUnspentOutputs(utxo)
|
||||
})
|
||||
|
||||
describe('choosing utxo', function(){
|
||||
it('calculates fees', function(){
|
||||
var tx = wallet.createTx(to, value)
|
||||
|
||||
assert.equal(tx.ins.length, 1)
|
||||
assert.deepEqual(tx.ins[0].hash, fakeTxHash(3))
|
||||
assert.equal(tx.ins[0].index, 0)
|
||||
})
|
||||
|
||||
describe('transaction fee', function(){
|
||||
it('allows fee to be specified', function(){
|
||||
var fee = 30000
|
||||
var tx = wallet.createTx(to, value, fee)
|
||||
|
||||
assert.equal(tx.ins.length, 2)
|
||||
|
||||
assert.deepEqual(tx.ins[0].hash, fakeTxHash(3))
|
||||
assert.equal(tx.ins[0].index, 0)
|
||||
assert.deepEqual(tx.ins[1].hash, fakeTxHash(2))
|
||||
assert.equal(tx.ins[1].index, 1)
|
||||
assert.equal(getFee(wallet, tx), fee)
|
||||
})
|
||||
|
||||
it('allows fee to be set to zero', function(){
|
||||
|
@ -421,6 +433,41 @@ describe('Wallet', function() {
|
|||
var fee = 0
|
||||
var tx = wallet.createTx(to, value, fee)
|
||||
|
||||
assert.equal(getFee(wallet, tx), fee)
|
||||
})
|
||||
|
||||
it('does not overestimate fees when network has dustSoftThreshold', function(){
|
||||
var wallet = new Wallet(seed, networks.litecoin)
|
||||
var address = wallet.generateAddress()
|
||||
wallet.setUnspentOutputs([{
|
||||
hash: fakeTxId(0),
|
||||
outputIndex: 0,
|
||||
address: address,
|
||||
value: 500000
|
||||
}])
|
||||
|
||||
value = 200000
|
||||
var tx = wallet.createTx(address, value)
|
||||
|
||||
assert.equal(getFee(wallet, tx), 100000)
|
||||
})
|
||||
|
||||
function getFee(wallet, tx) {
|
||||
var inputValue = tx.ins.reduce(function(memo, input){
|
||||
var id = Array.prototype.reverse.call(input.hash).toString('hex')
|
||||
return memo + wallet.outputs[id + ':' + input.index].value
|
||||
}, 0)
|
||||
|
||||
return tx.outs.reduce(function(memo, output){
|
||||
return memo - output.value
|
||||
}, inputValue)
|
||||
}
|
||||
})
|
||||
|
||||
describe('choosing utxo', function(){
|
||||
it('takes fees into account', function(){
|
||||
var tx = wallet.createTx(to, value)
|
||||
|
||||
assert.equal(tx.ins.length, 1)
|
||||
assert.deepEqual(tx.ins[0].hash, fakeTxHash(3))
|
||||
assert.equal(tx.ins[0].index, 0)
|
||||
|
@ -446,7 +493,7 @@ describe('Wallet', function() {
|
|||
})
|
||||
})
|
||||
|
||||
describe(networks.testnet, function(){
|
||||
describe('works for testnet', function(){
|
||||
it('should create transaction', function(){
|
||||
var wallet = new Wallet(seed, networks.testnet)
|
||||
var address = wallet.generateAddress()
|
||||
|
|
Loading…
Reference in a new issue