2014-04-10 17:57:41 -03:00
|
|
|
'use strict';
|
2014-08-14 11:51:56 -04:00
|
|
|
var Wallet = copay.Wallet;
|
2014-08-02 20:51:31 -03:00
|
|
|
var PrivateKey = copay.PrivateKey;
|
2014-09-25 01:58:27 -03:00
|
|
|
var Network = requireMock('FakeNetwork');
|
|
|
|
|
var Blockchain = requireMock('FakeBlockchain');
|
2014-06-09 17:28:56 -03:00
|
|
|
var TransactionBuilder = bitcore.TransactionBuilder;
|
2014-07-24 10:42:47 -03:00
|
|
|
var Transaction = bitcore.Transaction;
|
|
|
|
|
var Address = bitcore.Address;
|
2014-11-25 10:59:49 -03:00
|
|
|
var PayPro = bitcore.PayPro;
|
2014-11-25 13:29:03 -03:00
|
|
|
var Buffer = bitcore.Buffer;
|
2014-11-28 18:43:22 -03:00
|
|
|
var Script = bitcore.Script;
|
2014-04-15 15:50:22 -03:00
|
|
|
|
2014-09-29 10:18:47 -03:00
|
|
|
|
|
|
|
|
function assertObjectEqual(a, b) {
|
|
|
|
|
Wallet.PERSISTED_PROPERTIES.forEach(function(k) {
|
|
|
|
|
if (a[k] && b[k]) {
|
|
|
|
|
_.omit(a[k], 'name').should.be.deep.equal(b[k], k + ' differs');
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2014-08-21 19:04:08 -04:00
|
|
|
var walletConfig = {
|
2014-08-02 20:51:31 -03:00
|
|
|
requiredCopayers: 3,
|
|
|
|
|
totalCopayers: 5,
|
|
|
|
|
spendUnconfirmed: true,
|
|
|
|
|
reconnectDelay: 100,
|
|
|
|
|
networkName: 'testnet',
|
2014-10-07 18:33:55 -03:00
|
|
|
// network layer config
|
|
|
|
|
networkOpts: {
|
|
|
|
|
testnet: {
|
|
|
|
|
url: 'https://test-insight.bitpay.com:443',
|
|
|
|
|
transports: ['polling'],
|
|
|
|
|
},
|
|
|
|
|
livenet: {
|
|
|
|
|
url: 'https://insight.bitpay.com:443',
|
|
|
|
|
transports: ['polling'],
|
|
|
|
|
},
|
|
|
|
|
},
|
2014-08-02 20:51:31 -03:00
|
|
|
};
|
|
|
|
|
|
2014-10-07 18:33:55 -03:00
|
|
|
|
|
|
|
|
walletConfig.blockchainOpts = walletConfig.networkOpts;
|
|
|
|
|
|
|
|
|
|
|
2014-08-02 20:51:31 -03:00
|
|
|
var getNewEpk = function() {
|
|
|
|
|
return new PrivateKey({
|
2014-08-21 19:04:08 -04:00
|
|
|
networkName: walletConfig.networkName,
|
2014-08-22 14:44:40 -04:00
|
|
|
})
|
|
|
|
|
.deriveBIP45Branch()
|
|
|
|
|
.extendedPublicKeyString();
|
2014-08-02 20:51:31 -03:00
|
|
|
}
|
|
|
|
|
|
2014-06-03 13:07:31 -03:00
|
|
|
var addCopayers = function(w) {
|
|
|
|
|
for (var i = 0; i < 4; i++) {
|
2014-08-02 20:51:31 -03:00
|
|
|
w.publicKeyRing.addCopayer(getNewEpk());
|
2014-04-15 15:50:22 -03:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2014-04-16 21:10:04 -03:00
|
|
|
|
2014-11-05 22:05:09 -03:00
|
|
|
describe('Wallet model', function() {
|
2014-11-23 00:29:50 -03:00
|
|
|
var sandbox;
|
|
|
|
|
beforeEach(function() {
|
|
|
|
|
sandbox = sinon.sandbox.create();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
afterEach(function() {
|
|
|
|
|
sandbox.restore();
|
|
|
|
|
});
|
|
|
|
|
|
2014-06-03 13:07:31 -03:00
|
|
|
it('should fail to create an instance', function() {
|
|
|
|
|
(function() {
|
2014-08-21 19:04:08 -04:00
|
|
|
new Wallet(walletConfig)
|
2014-06-03 13:07:31 -03:00
|
|
|
}).should.
|
2014-08-22 14:44:40 -04:00
|
|
|
throw();
|
2014-04-10 17:57:41 -03:00
|
|
|
});
|
2014-06-18 10:09:40 -03:00
|
|
|
it('should getNetworkName', function() {
|
2014-06-24 17:48:05 -07:00
|
|
|
var w = cachedCreateW();
|
2014-06-18 10:09:40 -03:00
|
|
|
w.getNetworkName().should.equal('testnet');
|
|
|
|
|
});
|
2014-04-14 18:30:08 -03:00
|
|
|
|
2014-06-24 13:17:22 -03:00
|
|
|
|
2014-08-02 20:51:31 -03:00
|
|
|
var createW = function(N, conf) {
|
2014-06-09 17:52:08 -03:00
|
|
|
|
2014-08-21 19:04:08 -04:00
|
|
|
var c = JSON.parse(JSON.stringify(conf || walletConfig));
|
2014-06-09 17:52:08 -03:00
|
|
|
if (!N) N = c.totalCopayers;
|
2014-06-03 13:07:31 -03:00
|
|
|
|
2014-06-24 13:17:22 -03:00
|
|
|
var mainPrivateKey = new copay.PrivateKey({
|
2014-08-21 19:04:08 -04:00
|
|
|
networkName: walletConfig.networkName
|
2014-06-03 13:07:31 -03:00
|
|
|
});
|
2014-06-24 13:17:22 -03:00
|
|
|
var mainCopayerEPK = mainPrivateKey.deriveBIP45Branch().extendedPublicKeyString();
|
|
|
|
|
c.privateKey = mainPrivateKey;
|
2014-04-15 15:50:22 -03:00
|
|
|
|
2014-04-16 21:10:04 -03:00
|
|
|
c.publicKeyRing = new copay.PublicKeyRing({
|
|
|
|
|
networkName: c.networkName,
|
2014-06-09 17:52:08 -03:00
|
|
|
requiredCopayers: Math.min(N, c.requiredCopayers),
|
|
|
|
|
totalCopayers: N,
|
2014-04-16 21:10:04 -03:00
|
|
|
});
|
2014-06-24 13:17:22 -03:00
|
|
|
c.publicKeyRing.addCopayer(mainCopayerEPK);
|
2014-04-15 15:50:22 -03:00
|
|
|
|
2014-04-16 21:10:04 -03:00
|
|
|
c.txProposals = new copay.TxProposals({
|
|
|
|
|
networkName: c.networkName,
|
|
|
|
|
});
|
2014-06-24 13:17:22 -03:00
|
|
|
|
2014-10-07 18:33:55 -03:00
|
|
|
c.blockchain = new Blockchain(walletConfig.blockchain);
|
|
|
|
|
|
|
|
|
|
c.network = sinon.stub();
|
|
|
|
|
c.network.setHexNonce = sinon.stub();
|
|
|
|
|
c.network.setHexNonces = sinon.stub();
|
|
|
|
|
c.network.getHexNonce = sinon.stub();
|
|
|
|
|
c.network.getHexNonces = sinon.stub();
|
|
|
|
|
c.network.peerFromCopayer = sinon.stub().returns('xxxx');
|
|
|
|
|
c.network.send = sinon.stub();
|
|
|
|
|
|
2014-06-23 10:59:33 -03:00
|
|
|
c.addressBook = {
|
|
|
|
|
'2NFR2kzH9NUdp8vsXTB4wWQtTtzhpKxsyoJ': {
|
2014-06-18 20:18:13 -03:00
|
|
|
label: 'John',
|
|
|
|
|
copayerId: '026a55261b7c898fff760ebe14fd22a71892295f3b49e0ca66727bc0a0d7f94d03',
|
|
|
|
|
createdTs: 1403102115,
|
2014-07-07 01:33:39 -03:00
|
|
|
hidden: false
|
2014-06-23 10:59:33 -03:00
|
|
|
},
|
|
|
|
|
'2MtP8WyiwG7ZdVWM96CVsk2M1N8zyfiVQsY': {
|
2014-06-18 20:18:13 -03:00
|
|
|
label: 'Jennifer',
|
|
|
|
|
copayerId: '032991f836543a492bd6d0bb112552bfc7c5f3b7d5388fcbcbf2fbb893b44770d7',
|
|
|
|
|
createdTs: 1403103115,
|
2014-07-07 01:33:39 -03:00
|
|
|
hidden: false
|
2014-06-18 20:18:13 -03:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2014-08-21 19:04:08 -04:00
|
|
|
c.networkName = walletConfig.networkName;
|
2014-06-03 13:07:31 -03:00
|
|
|
c.version = '0.0.1';
|
2014-04-16 21:10:04 -03:00
|
|
|
|
|
|
|
|
return new Wallet(c);
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-24 17:48:05 -07:00
|
|
|
var cachedW = null;
|
|
|
|
|
var cachedWobj = null;
|
|
|
|
|
var cachedCreateW = function() {
|
|
|
|
|
if (!cachedW) {
|
|
|
|
|
cachedW = createW();
|
|
|
|
|
cachedWobj = cachedW.toObj();
|
|
|
|
|
cachedWobj.opts.reconnectDelay = 100;
|
|
|
|
|
}
|
2014-10-07 18:33:55 -03:00
|
|
|
Wallet._newAsync = sinon.stub().returns(new Network(walletConfig.network));
|
|
|
|
|
Wallet._newInsight = sinon.stub().returns(new Blockchain(walletConfig.blockchain));
|
|
|
|
|
|
|
|
|
|
var w = Wallet.fromObj(cachedWobj, {
|
|
|
|
|
blockchainOpts: {},
|
|
|
|
|
networkOpts: {},
|
|
|
|
|
});
|
2014-06-24 17:48:05 -07:00
|
|
|
return w;
|
|
|
|
|
};
|
|
|
|
|
|
2014-06-03 13:07:31 -03:00
|
|
|
it('should create an instance', function() {
|
2014-06-24 17:48:05 -07:00
|
|
|
var w = cachedCreateW();
|
2014-04-16 21:10:04 -03:00
|
|
|
should.exist(w);
|
|
|
|
|
w.publicKeyRing.walletId.should.equal(w.id);
|
|
|
|
|
w.txProposals.walletId.should.equal(w.id);
|
|
|
|
|
w.requiredCopayers.should.equal(3);
|
2014-04-15 15:50:22 -03:00
|
|
|
should.exist(w.id);
|
|
|
|
|
should.exist(w.publicKeyRing);
|
|
|
|
|
should.exist(w.privateKey);
|
|
|
|
|
should.exist(w.txProposals);
|
2014-06-18 01:00:32 -03:00
|
|
|
should.exist(w.addressBook);
|
2014-04-15 15:50:22 -03:00
|
|
|
});
|
|
|
|
|
|
2014-11-28 18:43:22 -03:00
|
|
|
it('should provide some basic features', function() {
|
2014-04-15 15:50:22 -03:00
|
|
|
var opts = {};
|
2014-06-24 17:48:05 -07:00
|
|
|
var w = cachedCreateW();
|
2014-04-15 15:50:22 -03:00
|
|
|
addCopayers(w);
|
2014-07-03 11:18:01 -03:00
|
|
|
w.publicKeyRing.generateAddress(false, w.publicKey);
|
2014-04-15 15:50:22 -03:00
|
|
|
w.publicKeyRing.isComplete().should.equal(true);
|
2014-11-28 18:43:22 -03:00
|
|
|
(new bitcore.Address(w.generateAddress(true))).isValid().should.equal(true);
|
2014-04-14 18:30:08 -03:00
|
|
|
});
|
|
|
|
|
|
2014-06-03 13:07:31 -03:00
|
|
|
var unspentTest = [{
|
2014-04-15 18:23:35 -03:00
|
|
|
"address": "dummy",
|
|
|
|
|
"scriptPubKey": "dummy",
|
|
|
|
|
"txid": "2ac165fa7a3a2b535d106a0041c7568d03b531e58aeccdd3199d7289ab12cfc1",
|
|
|
|
|
"vout": 1,
|
|
|
|
|
"amount": 10,
|
2014-06-03 13:07:31 -03:00
|
|
|
"confirmations": 7
|
|
|
|
|
}];
|
2014-04-15 18:23:35 -03:00
|
|
|
|
2014-06-19 10:30:53 -03:00
|
|
|
var createW2 = function(privateKeys, N, conf) {
|
2014-06-09 17:52:08 -03:00
|
|
|
if (!N) N = 3;
|
2014-08-02 20:51:31 -03:00
|
|
|
var w = createW(N, conf);
|
2014-04-15 18:23:35 -03:00
|
|
|
should.exist(w);
|
|
|
|
|
|
2014-06-03 13:07:31 -03:00
|
|
|
var pkr = w.publicKeyRing;
|
2014-04-15 18:23:35 -03:00
|
|
|
|
2014-06-13 11:30:48 -03:00
|
|
|
for (var i = 0; i < N - 1; i++) {
|
2014-04-17 17:01:31 -03:00
|
|
|
if (privateKeys) {
|
2014-06-03 13:07:31 -03:00
|
|
|
var k = privateKeys[i];
|
2014-08-02 20:51:31 -03:00
|
|
|
pkr.addCopayer(k ? k.deriveBIP45Branch().extendedPublicKeyString() : getNewEpk());
|
2014-05-29 17:18:55 -03:00
|
|
|
} else {
|
2014-08-02 20:51:31 -03:00
|
|
|
pkr.addCopayer(getNewEpk());
|
2014-05-29 17:18:55 -03:00
|
|
|
}
|
2014-04-15 18:23:35 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return w;
|
|
|
|
|
};
|
|
|
|
|
|
2014-06-24 17:48:05 -07:00
|
|
|
var cachedW2 = null;
|
|
|
|
|
var cachedW2obj = null;
|
|
|
|
|
var cachedCreateW2 = function() {
|
|
|
|
|
if (!cachedW2) {
|
|
|
|
|
cachedW2 = createW2();
|
|
|
|
|
cachedW2obj = cachedW2.toObj();
|
|
|
|
|
cachedW2obj.opts.reconnectDelay = 100;
|
|
|
|
|
}
|
2014-10-07 18:33:55 -03:00
|
|
|
Wallet._newAsync = sinon.stub().returns(new Network(walletConfig.network));
|
|
|
|
|
Wallet._newInsight = sinon.stub().returns(new Blockchain(walletConfig.blockchain));
|
|
|
|
|
|
|
|
|
|
var w = Wallet.fromObj(cachedW2obj, {
|
|
|
|
|
blockchainOpts: {},
|
|
|
|
|
networkOpts: {},
|
|
|
|
|
});
|
2014-11-23 00:29:50 -03:00
|
|
|
if (w.httpUtil.request.restore)
|
|
|
|
|
w.httpUtil.request.restore();
|
2014-06-24 17:48:05 -07:00
|
|
|
return w;
|
|
|
|
|
};
|
|
|
|
|
|
2014-11-28 18:43:22 -03:00
|
|
|
var unSpentTestFromWallet = function(w, addrStr) {
|
2014-10-07 18:33:55 -03:00
|
|
|
|
2014-11-28 18:43:22 -03:00
|
|
|
unspentTest[0].address = addrStr;
|
|
|
|
|
var a = new bitcore.Address(addrStr);
|
|
|
|
|
unspentTest[0].scriptPubKey = Script.createP2SH(a.payload()).getBuffer().toString('hex');
|
|
|
|
|
};
|
2014-04-15 18:23:35 -03:00
|
|
|
|
|
|
|
|
|
2014-11-28 18:43:22 -03:00
|
|
|
it('#create, fail for network', function() {
|
2014-04-15 18:23:35 -03:00
|
|
|
|
2014-11-28 18:43:22 -03:00
|
|
|
var w = cachedCreateW2();
|
|
|
|
|
unSpentTestFromWallet(unspentTest[0], w.publicKeyRing.generateAddress(true));
|
2014-07-04 12:51:27 -03:00
|
|
|
var f = function() {
|
2014-11-26 17:25:57 -03:00
|
|
|
w._createTxProposal(
|
2014-07-04 12:51:27 -03:00
|
|
|
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
|
|
|
|
'123456789',
|
|
|
|
|
null,
|
|
|
|
|
unspentTest
|
|
|
|
|
);
|
|
|
|
|
};
|
2014-11-28 18:43:22 -03:00
|
|
|
f.should.throw('networkname');
|
2014-07-04 12:51:27 -03:00
|
|
|
});
|
|
|
|
|
|
2014-04-15 18:23:35 -03:00
|
|
|
|
2014-11-22 20:00:18 -03:00
|
|
|
|
2014-09-09 08:42:32 -03:00
|
|
|
it('#create, check builder opts', function() {
|
|
|
|
|
var w = cachedCreateW2();
|
2014-11-28 18:43:22 -03:00
|
|
|
unSpentTestFromWallet(unspentTest[0], w.publicKeyRing.generateAddress(true));
|
2014-11-23 17:41:34 -03:00
|
|
|
var txp = w._createTxProposal(
|
2014-09-09 08:42:32 -03:00
|
|
|
'mgGJEugdPnvhmRuFdbdQcFfoFLc1XXeB79',
|
|
|
|
|
'123456789',
|
|
|
|
|
null,
|
|
|
|
|
unspentTest
|
|
|
|
|
);
|
2014-11-22 20:00:18 -03:00
|
|
|
var opts = JSON.parse(txp.builder.vanilla.opts);
|
2014-09-09 08:42:32 -03:00
|
|
|
opts.signhash.should.equal(1);
|
2014-09-10 15:09:11 -03:00
|
|
|
(opts.lockTime === null).should.be.true;
|
2014-09-09 08:42:32 -03:00
|
|
|
should.not.exist(opts.fee);
|
|
|
|
|
should.not.exist(opts.feeSat);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('#create, 1 sign', function() {
|
2014-06-24 17:48:05 -07:00
|
|
|
var w = cachedCreateW2();
|
2014-11-28 18:43:22 -03:00
|
|
|
unSpentTestFromWallet(unspentTest[0], w.publicKeyRing.generateAddress(true));
|
2014-04-15 18:23:35 -03:00
|
|
|
|
2014-11-23 17:41:34 -03:00
|
|
|
var txp = w._createTxProposal(
|
2014-07-04 12:51:27 -03:00
|
|
|
'mgGJEugdPnvhmRuFdbdQcFfoFLc1XXeB79',
|
2014-06-03 13:07:31 -03:00
|
|
|
'123456789',
|
2014-06-13 10:33:30 -03:00
|
|
|
null,
|
2014-04-15 18:23:35 -03:00
|
|
|
unspentTest
|
|
|
|
|
);
|
|
|
|
|
|
2014-11-26 15:15:12 -03:00
|
|
|
Object.keys(txp.getSignersPubKeys()).length.should.equal(1);
|
2014-05-29 17:18:55 -03:00
|
|
|
var tx = txp.builder.build();
|
2014-04-15 18:23:35 -03:00
|
|
|
should.exist(tx);
|
2014-06-13 10:33:30 -03:00
|
|
|
chai.expect(txp.comment).to.be.null;
|
2014-04-15 18:23:35 -03:00
|
|
|
tx.isComplete().should.equal(false);
|
2014-05-29 17:18:55 -03:00
|
|
|
Object.keys(txp.seenBy).length.should.equal(1);
|
2014-11-23 17:41:34 -03:00
|
|
|
Object.keys(txp.signedBy).length.should.equal(1);
|
2014-04-15 18:23:35 -03:00
|
|
|
});
|
|
|
|
|
|
2014-06-13 10:33:30 -03:00
|
|
|
it('#create with comment', function() {
|
|
|
|
|
|
2014-06-24 17:48:05 -07:00
|
|
|
var w = cachedCreateW2();
|
2014-06-13 10:33:30 -03:00
|
|
|
var comment = 'This is a comment';
|
2014-11-28 18:43:22 -03:00
|
|
|
unSpentTestFromWallet(unspentTest[0], w.publicKeyRing.generateAddress(true));
|
2014-06-13 10:33:30 -03:00
|
|
|
|
2014-11-23 17:41:34 -03:00
|
|
|
var txp = w._createTxProposal(
|
2014-07-04 12:51:27 -03:00
|
|
|
'mgGJEugdPnvhmRuFdbdQcFfoFLc1XXeB79',
|
2014-06-13 10:33:30 -03:00
|
|
|
'123456789',
|
|
|
|
|
comment,
|
|
|
|
|
unspentTest
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
var tx = txp.builder.build();
|
|
|
|
|
should.exist(tx);
|
|
|
|
|
txp.comment.should.equal(comment);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('#create throw exception on long comment', function() {
|
|
|
|
|
|
2014-06-24 17:48:05 -07:00
|
|
|
var w = cachedCreateW2();
|
2014-06-13 10:33:30 -03:00
|
|
|
var comment = 'Lorem ipsum dolor sit amet, suas euismod vis te, velit deleniti vix an. Pri ex suscipit similique, inermis per';
|
2014-11-28 18:43:22 -03:00
|
|
|
unSpentTestFromWallet(unspentTest[0], w.publicKeyRing.generateAddress(true));
|
2014-06-13 10:33:30 -03:00
|
|
|
|
2014-11-22 20:00:18 -03:00
|
|
|
(function() {
|
2014-11-23 17:41:34 -03:00
|
|
|
w._createTxProposal(
|
2014-07-04 12:51:27 -03:00
|
|
|
'mgGJEugdPnvhmRuFdbdQcFfoFLc1XXeB79',
|
2014-06-13 10:33:30 -03:00
|
|
|
'123456789',
|
|
|
|
|
comment,
|
|
|
|
|
unspentTest
|
|
|
|
|
);
|
2014-11-22 20:00:18 -03:00
|
|
|
}).should.throw('Comment');
|
2014-06-13 10:33:30 -03:00
|
|
|
});
|
|
|
|
|
|
2014-06-03 13:07:31 -03:00
|
|
|
it('#addressIsOwn', function() {
|
2014-11-13 17:34:13 -03:00
|
|
|
var wallet = cachedCreateW2();
|
2014-11-29 18:35:48 -03:00
|
|
|
var allAddresses = wallet.getAddresses();
|
2014-11-13 17:34:13 -03:00
|
|
|
for (var i = 0; i < allAddresses.length; i++) {
|
|
|
|
|
wallet.addressIsOwn(allAddresses[i]).should.equal(true);
|
|
|
|
|
}
|
2014-05-01 11:04:21 -03:00
|
|
|
|
2014-11-13 17:34:13 -03:00
|
|
|
wallet.addressIsOwn('mmHqhvTVbxgJTnePa7cfweSRjBCy9bQQXJ').should.equal(false);
|
|
|
|
|
wallet.addressIsOwn('mgtUfP9sTJ6vPLoBxZLPEccGpcjNVryaCX').should.equal(false);
|
2014-04-18 11:19:39 -03:00
|
|
|
});
|
2014-04-15 18:23:35 -03:00
|
|
|
|
2014-06-03 13:07:31 -03:00
|
|
|
it('#create. Signing with derivate keys', function() {
|
2014-04-15 18:23:35 -03:00
|
|
|
|
2014-06-24 17:48:05 -07:00
|
|
|
var w = cachedCreateW2();
|
2014-04-15 18:23:35 -03:00
|
|
|
|
|
|
|
|
var ts = Date.now();
|
2014-06-24 13:17:22 -03:00
|
|
|
for (var isChange = false; !isChange; isChange = true) {
|
2014-06-03 13:07:31 -03:00
|
|
|
for (var index = 0; index < 3; index++) {
|
2014-11-28 18:43:22 -03:00
|
|
|
unSpentTestFromWallet(unspentTest[0], w.publicKeyRing.generateAddress(true));
|
2014-11-23 17:41:34 -03:00
|
|
|
var txp = w._createTxProposal(
|
2014-07-04 12:51:27 -03:00
|
|
|
'mgGJEugdPnvhmRuFdbdQcFfoFLc1XXeB79',
|
2014-06-03 13:07:31 -03:00
|
|
|
'123456789',
|
2014-06-13 10:33:30 -03:00
|
|
|
null,
|
2014-04-15 18:23:35 -03:00
|
|
|
unspentTest
|
|
|
|
|
);
|
2014-11-22 20:00:18 -03:00
|
|
|
var tx = txp.builder.build();
|
2014-04-15 18:23:35 -03:00
|
|
|
should.exist(tx);
|
|
|
|
|
tx.isComplete().should.equal(false);
|
|
|
|
|
tx.countInputMissingSignatures(0).should.equal(2);
|
|
|
|
|
|
2014-11-22 20:00:18 -03:00
|
|
|
(txp.signedBy[w.privateKey.getId()] - ts > 0).should.equal(true);
|
|
|
|
|
(txp.seenBy[w.privateKey.getId()] - ts > 0).should.equal(true);
|
2014-04-15 18:23:35 -03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2014-06-03 13:07:31 -03:00
|
|
|
it('#fromObj #toObj round trip', function() {
|
2014-04-28 12:02:43 -03:00
|
|
|
|
2014-06-24 17:48:05 -07:00
|
|
|
var w = cachedCreateW2();
|
2014-04-28 12:02:43 -03:00
|
|
|
|
|
|
|
|
var o = w.toObj();
|
|
|
|
|
o = JSON.parse(JSON.stringify(o));
|
|
|
|
|
|
2014-06-09 20:08:12 -03:00
|
|
|
// non stored options
|
2014-06-13 11:30:48 -03:00
|
|
|
o.opts.reconnectDelay = 100;
|
2014-06-09 20:08:12 -03:00
|
|
|
|
2014-10-07 18:33:55 -03:00
|
|
|
var w2 = Wallet.fromObj(o, {
|
|
|
|
|
blockchainOpts: {},
|
|
|
|
|
networkOpts: {},
|
|
|
|
|
});
|
2014-08-22 14:44:40 -04:00
|
|
|
should.exist(w2);
|
|
|
|
|
w2.publicKeyRing.requiredCopayers.should.equal(w.publicKeyRing.requiredCopayers);
|
|
|
|
|
should.exist(w2.publicKeyRing.getCopayerId);
|
|
|
|
|
should.exist(w2.txProposals.toObj);
|
|
|
|
|
should.exist(w2.privateKey.toObj);
|
2014-04-28 12:02:43 -03:00
|
|
|
});
|
|
|
|
|
|
2014-06-03 13:07:31 -03:00
|
|
|
it('#getSecret decodeSecret', function() {
|
2014-06-24 17:48:05 -07:00
|
|
|
var w = cachedCreateW2();
|
2014-04-30 12:58:40 -03:00
|
|
|
var id = w.getMyCopayerId();
|
2014-09-03 16:51:02 -03:00
|
|
|
var secretNumber = w.getSecretNumber();
|
2014-04-30 12:58:40 -03:00
|
|
|
|
2014-06-03 13:07:31 -03:00
|
|
|
var sb = w.getSecret();
|
2014-04-30 12:58:40 -03:00
|
|
|
should.exist(sb);
|
2014-09-03 16:51:02 -03:00
|
|
|
|
2014-04-30 12:58:40 -03:00
|
|
|
var s = Wallet.decodeSecret(sb);
|
|
|
|
|
s.pubKey.should.equal(id);
|
2014-09-03 16:51:02 -03:00
|
|
|
s.secretNumber.should.equal(secretNumber);
|
2014-09-09 17:08:59 -07:00
|
|
|
s.networkName.should.equal(w.getNetworkName());
|
|
|
|
|
});
|
2014-04-30 12:58:40 -03:00
|
|
|
|
2014-09-09 17:08:59 -07:00
|
|
|
it('#getSecret decodeSecret livenet', function() {
|
|
|
|
|
var w = cachedCreateW2();
|
|
|
|
|
var stub = sinon.stub(w, 'getNetworkName');
|
|
|
|
|
stub.returns('livenet');
|
|
|
|
|
var sb = w.getSecret();
|
|
|
|
|
should.exist(sb);
|
|
|
|
|
var s = Wallet.decodeSecret(sb);
|
|
|
|
|
s.networkName.should.equal('livenet');
|
|
|
|
|
stub.restore();
|
2014-04-30 12:58:40 -03:00
|
|
|
});
|
2014-09-03 16:51:02 -03:00
|
|
|
|
|
|
|
|
|
2014-06-03 13:07:31 -03:00
|
|
|
it('decodeSecret check', function() {
|
2014-10-10 12:02:46 -03:00
|
|
|
var s = Wallet.decodeSecret('4fp61K187CsYmjoRQC5iAdC5eGmbCRsAAXfwEwetSQgHvZs27eWKaLaNHRoKM');
|
|
|
|
|
should.exist(s);
|
2014-09-03 16:51:02 -03:00
|
|
|
|
2014-10-22 16:57:29 -03:00
|
|
|
s = Wallet.decodeSecret('4fp61K187CsYmjoRQC5iAdC5eGmbCRsAAXfwEwetSQgHvZs27eWKaLaNHRoK');
|
2014-10-10 12:02:46 -03:00
|
|
|
s.should.equal(false);
|
2014-09-10 15:09:11 -03:00
|
|
|
|
2014-10-10 12:02:46 -03:00
|
|
|
|
2014-10-22 16:57:29 -03:00
|
|
|
s = Wallet.decodeSecret('123456');
|
2014-10-10 12:02:46 -03:00
|
|
|
s.should.equal(false);
|
2014-06-03 13:07:31 -03:00
|
|
|
});
|
2014-06-09 10:30:37 -03:00
|
|
|
|
2014-08-21 13:12:55 -04:00
|
|
|
|
2014-08-21 13:54:38 -04:00
|
|
|
it('#maxRejectCount', function() {
|
2014-08-21 13:12:55 -04:00
|
|
|
var w = cachedCreateW();
|
|
|
|
|
w.maxRejectCount().should.equal(2);
|
|
|
|
|
});
|
|
|
|
|
|
2014-09-30 13:04:48 -03:00
|
|
|
describe('#getMaxRequiredCopayers', function() {
|
|
|
|
|
it('should return ', function() {
|
|
|
|
|
var validPairs = {
|
|
|
|
|
1: 1,
|
|
|
|
|
2: 2,
|
|
|
|
|
3: 3,
|
|
|
|
|
4: 4,
|
|
|
|
|
5: 4,
|
|
|
|
|
6: 3,
|
|
|
|
|
7: 3,
|
|
|
|
|
8: 2,
|
|
|
|
|
9: 2,
|
|
|
|
|
10: 2,
|
|
|
|
|
11: 1,
|
|
|
|
|
12: 1,
|
|
|
|
|
};
|
|
|
|
|
_.each(validPairs, function(maxReq, total) {
|
|
|
|
|
Wallet.getMaxRequiredCopayers(total).should.equal(maxReq);
|
|
|
|
|
})
|
|
|
|
|
});
|
|
|
|
|
});
|
2014-08-21 13:12:55 -04:00
|
|
|
|
2014-09-16 15:58:23 -03:00
|
|
|
describe('#_onData', function() {
|
|
|
|
|
var w = cachedCreateW();
|
|
|
|
|
var sender = '025c046aaf505a6d23203edd343132e9d4d21818b962d1e9a9c98573cc2031bfc9';
|
|
|
|
|
var ts = 1410810974778246;
|
|
|
|
|
it('should fail on message unknown', function() {
|
|
|
|
|
var data = {
|
|
|
|
|
type: "xxx",
|
|
|
|
|
walletId: w.id
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
(function() {
|
|
|
|
|
w._onData(sender, data, ts);
|
|
|
|
|
}).should.
|
|
|
|
|
throw('unknown message type received: xxx from: 025c046aaf505a6d23203edd343132e9d4d21818b962d1e9a9c98573cc2031bfc9');
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should call sendWalletReady', function() {
|
|
|
|
|
var data = {
|
|
|
|
|
type: "walletId",
|
|
|
|
|
walletId: w.id
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var spy = sinon.spy(w, 'sendWalletReady');
|
|
|
|
|
w._onData(sender, data, ts);
|
|
|
|
|
sinon.assert.callCount(spy, 1);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
2014-08-21 13:12:55 -04:00
|
|
|
describe('#purgeTxProposals', function() {
|
|
|
|
|
it('should delete all', function() {
|
|
|
|
|
var w = cachedCreateW();
|
|
|
|
|
var spy1 = sinon.spy(w.txProposals, 'deleteAll');
|
|
|
|
|
var spy2 = sinon.spy(w.txProposals, 'deletePending');
|
|
|
|
|
w.purgeTxProposals(1);
|
|
|
|
|
spy1.callCount.should.equal(1);
|
|
|
|
|
spy2.callCount.should.equal(0);
|
2014-08-21 13:54:38 -04:00
|
|
|
spy1.restore();
|
|
|
|
|
spy2.restore();
|
2014-08-21 13:12:55 -04:00
|
|
|
});
|
|
|
|
|
it('should delete pending', function() {
|
|
|
|
|
var w = cachedCreateW();
|
|
|
|
|
var spy1 = sinon.spy(w.txProposals, 'deleteAll');
|
|
|
|
|
var spy2 = sinon.spy(w.txProposals, 'deletePending');
|
|
|
|
|
w.purgeTxProposals();
|
|
|
|
|
spy1.callCount.should.equal(0);
|
|
|
|
|
spy2.callCount.should.equal(1);
|
2014-08-21 13:54:38 -04:00
|
|
|
spy1.restore();
|
|
|
|
|
spy2.restore();
|
2014-08-21 13:12:55 -04:00
|
|
|
});
|
|
|
|
|
it('should count deletions', function() {
|
|
|
|
|
var w = cachedCreateW();
|
|
|
|
|
var s = sinon.stub(w.txProposals, 'length').returns(10);
|
|
|
|
|
var n = w.purgeTxProposals();
|
|
|
|
|
n.should.equal(0);
|
2014-08-21 13:54:38 -04:00
|
|
|
s.restore();
|
2014-08-21 13:12:55 -04:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
2014-07-08 19:52:47 -03:00
|
|
|
//this test fails randomly
|
|
|
|
|
it.skip('call reconnect after interval', function(done) {
|
2014-06-15 21:19:21 -07:00
|
|
|
this.timeout(10000);
|
2014-06-24 17:48:05 -07:00
|
|
|
var w = cachedCreateW2();
|
2014-06-03 13:07:31 -03:00
|
|
|
var spy = sinon.spy(w, 'scheduleConnect');
|
2014-06-18 11:08:50 -03:00
|
|
|
var callCount = 3;
|
2014-06-03 13:07:31 -03:00
|
|
|
w.netStart();
|
|
|
|
|
setTimeout(function() {
|
2014-06-09 20:08:12 -03:00
|
|
|
sinon.assert.callCount(spy, callCount);
|
2014-06-03 13:07:31 -03:00
|
|
|
done();
|
2014-06-23 10:59:33 -03:00
|
|
|
}, w.reconnectDelay * callCount * (callCount + 1) / 2);
|
2014-04-30 12:58:40 -03:00
|
|
|
});
|
2014-06-09 10:30:37 -03:00
|
|
|
|
2014-08-04 16:27:58 -03:00
|
|
|
it('#isSingleUser', function() {
|
|
|
|
|
var w = createW();
|
|
|
|
|
w.isShared().should.equal(true);
|
|
|
|
|
|
|
|
|
|
w.totalCopayers = 1;
|
|
|
|
|
w.isShared().should.equal(false);
|
|
|
|
|
});
|
|
|
|
|
|
2014-08-21 13:12:55 -04:00
|
|
|
|
|
|
|
|
|
2014-11-30 00:31:17 -03:00
|
|
|
it('#isComplete', function() {
|
2014-07-08 11:52:24 -03:00
|
|
|
var w = createW();
|
|
|
|
|
w.publicKeyRing.isComplete().should.equal(false);
|
2014-11-30 00:31:17 -03:00
|
|
|
w.isComplete().should.equal(false);
|
2014-07-08 11:52:24 -03:00
|
|
|
|
|
|
|
|
var w2 = createW2();
|
|
|
|
|
w2.publicKeyRing.isComplete().should.equal(true);
|
2014-11-30 00:31:17 -03:00
|
|
|
w2.isComplete().should.equal(true);
|
2014-07-08 11:52:24 -03:00
|
|
|
});
|
|
|
|
|
|
2014-06-09 10:30:37 -03:00
|
|
|
it('handle network indexes correctly', function() {
|
|
|
|
|
var w = createW();
|
|
|
|
|
var aiObj = {
|
2014-07-01 09:41:28 -03:00
|
|
|
indexes: [{
|
2014-07-29 13:09:47 -03:00
|
|
|
copayerIndex: 0,
|
2014-07-01 09:41:28 -03:00
|
|
|
changeIndex: 3,
|
|
|
|
|
receiveIndex: 2
|
|
|
|
|
}]
|
2014-06-09 10:30:37 -03:00
|
|
|
};
|
2014-08-19 12:50:49 -04:00
|
|
|
w._onIndexes('senderID', aiObj, true);
|
2014-07-29 13:09:47 -03:00
|
|
|
w.publicKeyRing.getHDParams(0).getReceiveIndex(2);
|
|
|
|
|
w.publicKeyRing.getHDParams(0).getChangeIndex(3);
|
2014-06-09 10:30:37 -03:00
|
|
|
});
|
|
|
|
|
|
2014-06-09 11:19:38 -03:00
|
|
|
it('handle network pubKeyRings correctly', function() {
|
2014-06-09 10:30:37 -03:00
|
|
|
var w = createW();
|
2014-06-09 20:08:12 -03:00
|
|
|
w.getNetworkName().should.equal('testnet');
|
2014-06-09 10:30:37 -03:00
|
|
|
var cepk = [
|
|
|
|
|
w.publicKeyRing.toObj().copayersExtPubKeys[0],
|
2014-06-09 17:28:56 -03:00
|
|
|
'tpubDEqHs8LoCB1MDfXs1y2WaLJqPkKsgt8mDoQUFsQ4aKHvho5oFJkF7UrZnfFXKMhA1MuVPwq8a5VhFHvCquYcCVHeCrW4ZCWoDDE9K95e8rP',
|
|
|
|
|
'tpubDEqHs8LoCB1MGGKRyouphPdFNNuay5PBzCuJkgDSiWeAST8m7y4nwPZ7M27mUNWLLPDp6n8kp4P57sd8xHXNnZvap8PxWrUMvXzkxFNgCh7',
|
2014-06-09 10:30:37 -03:00
|
|
|
];
|
|
|
|
|
var pkrObj = {
|
|
|
|
|
walletId: w.id,
|
|
|
|
|
networkName: w.networkName,
|
|
|
|
|
requiredCopayers: w.requiredCopayers,
|
|
|
|
|
totalCopayers: w.totalCopayers,
|
2014-07-01 09:41:28 -03:00
|
|
|
indexes: [{
|
2014-07-29 13:09:47 -03:00
|
|
|
copayerIndex: 0,
|
2014-06-09 10:30:37 -03:00
|
|
|
changeIndex: 2,
|
|
|
|
|
receiveIndex: 3
|
2014-07-01 09:41:28 -03:00
|
|
|
}],
|
2014-06-09 10:30:37 -03:00
|
|
|
copayersExtPubKeys: cepk,
|
|
|
|
|
nicknameFor: {},
|
|
|
|
|
};
|
2014-08-19 12:51:08 -04:00
|
|
|
w._onPublicKeyRing('senderID', {
|
2014-06-09 10:30:37 -03:00
|
|
|
publicKeyRing: pkrObj
|
|
|
|
|
}, true);
|
2014-07-29 13:09:47 -03:00
|
|
|
w.publicKeyRing.getHDParams(0).getReceiveIndex(2);
|
|
|
|
|
w.publicKeyRing.getHDParams(0).getChangeIndex(3);
|
2014-06-09 10:30:37 -03:00
|
|
|
for (var i = 0; i < w.requiredCopayers; i++) {
|
|
|
|
|
w.publicKeyRing.toObj().copayersExtPubKeys[i].should.equal(cepk[i]);
|
|
|
|
|
}
|
|
|
|
|
});
|
2014-06-09 11:19:38 -03:00
|
|
|
|
|
|
|
|
var newId = '00bacacafe';
|
|
|
|
|
it('handle new connections', function(done) {
|
|
|
|
|
var w = createW();
|
2014-10-07 18:33:55 -03:00
|
|
|
w.sendWalletId = sinon.stub();
|
|
|
|
|
|
2014-06-09 11:19:38 -03:00
|
|
|
w.on('connect', function(id) {
|
2014-10-07 18:33:55 -03:00
|
|
|
id.should.equal('xxxx');
|
2014-06-09 11:19:38 -03:00
|
|
|
done();
|
|
|
|
|
});
|
2014-08-19 12:51:55 -04:00
|
|
|
w._onConnect(newId);
|
2014-06-09 11:19:38 -03:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should register new copayers correctly', function() {
|
|
|
|
|
var w = createW();
|
|
|
|
|
var r = w.getRegisteredCopayerIds();
|
|
|
|
|
r.length.should.equal(1);
|
2014-08-02 20:51:31 -03:00
|
|
|
w.publicKeyRing.addCopayer(getNewEpk());
|
|
|
|
|
|
2014-06-09 11:19:38 -03:00
|
|
|
r = w.getRegisteredCopayerIds();
|
|
|
|
|
r.length.should.equal(2);
|
|
|
|
|
r[0].should.not.equal(r[1]);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should register new peers correctly', function() {
|
|
|
|
|
var w = createW();
|
|
|
|
|
var r = w.getRegisteredPeerIds();
|
|
|
|
|
r.length.should.equal(1);
|
2014-08-02 20:51:31 -03:00
|
|
|
w.publicKeyRing.addCopayer(getNewEpk());
|
2014-06-09 11:19:38 -03:00
|
|
|
r = w.getRegisteredPeerIds();
|
|
|
|
|
r.length.should.equal(2);
|
|
|
|
|
r[0].should.not.equal(r[1]);
|
|
|
|
|
});
|
2014-06-12 17:42:26 -03:00
|
|
|
|
|
|
|
|
it('#getBalance should call #getUnspent', function(done) {
|
2014-06-24 17:48:05 -07:00
|
|
|
var w = cachedCreateW2();
|
2014-06-12 17:42:26 -03:00
|
|
|
var spy = sinon.spy(w.blockchain, 'getUnspent');
|
|
|
|
|
w.generateAddress();
|
|
|
|
|
w.getBalance(function(err, balance, balanceByAddr, safeBalance) {
|
|
|
|
|
sinon.assert.callCount(spy, 1);
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
2014-06-16 12:44:18 -03:00
|
|
|
it('#getBalance should return values in satoshis', function(done) {
|
2014-06-24 17:48:05 -07:00
|
|
|
var w = cachedCreateW2();
|
2014-06-12 17:42:26 -03:00
|
|
|
w.generateAddress();
|
|
|
|
|
w.getBalance(function(err, balance, balanceByAddr, safeBalance) {
|
2014-06-16 12:44:18 -03:00
|
|
|
balance.should.equal(2500010000);
|
|
|
|
|
safeBalance.should.equal(2500010000);
|
|
|
|
|
balanceByAddr.mji7zocy8QzYywQakwWf99w9bCT6orY1C1.should.equal(2500010000);
|
2014-06-12 17:42:26 -03:00
|
|
|
Object.keys(balanceByAddr).length.should.equal(1);
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2014-06-19 10:30:53 -03:00
|
|
|
it('#getUnspent should honor spendUnconfirmed = false', function(done) {
|
2014-08-21 19:04:08 -04:00
|
|
|
var conf = JSON.parse(JSON.stringify(walletConfig));
|
2014-06-19 10:30:53 -03:00
|
|
|
conf.spendUnconfirmed = false;
|
|
|
|
|
var w = createW2(null, null, conf);
|
|
|
|
|
w.getBalance(function(err, balance, balanceByAddr, safeBalance) {
|
|
|
|
|
balance.should.equal(2500010000);
|
|
|
|
|
safeBalance.should.equal(0);
|
|
|
|
|
balanceByAddr.mji7zocy8QzYywQakwWf99w9bCT6orY1C1.should.equal(2500010000);
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('#getUnspent and spendUnconfirmed should count transactions with 1 confirmations', function(done) {
|
2014-08-21 19:04:08 -04:00
|
|
|
var conf = JSON.parse(JSON.stringify(walletConfig));
|
2014-06-19 10:30:53 -03:00
|
|
|
conf.spendUnconfirmed = false;
|
2014-06-24 17:48:05 -07:00
|
|
|
var w = cachedCreateW2(null, null, conf);
|
2014-06-19 10:30:53 -03:00
|
|
|
w.blockchain.getUnspent = w.blockchain.getUnspent2;
|
|
|
|
|
w.getBalance(function(err, balance, balanceByAddr, safeBalance) {
|
|
|
|
|
balance.should.equal(2500010000);
|
|
|
|
|
safeBalance.should.equal(2500010000);
|
|
|
|
|
balanceByAddr.mji7zocy8QzYywQakwWf99w9bCT6orY1C1.should.equal(2500010000);
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2014-06-13 11:30:48 -03:00
|
|
|
var roundErrorChecks = [{
|
2014-08-22 14:44:40 -04:00
|
|
|
unspent: [1.0001],
|
|
|
|
|
balance: 100010000
|
|
|
|
|
}, {
|
|
|
|
|
unspent: [1.0002, 1.0003, 1.0004],
|
|
|
|
|
balance: 300090000
|
|
|
|
|
}, {
|
|
|
|
|
unspent: [0.000002, 1.000003, 2.000004],
|
|
|
|
|
balance: 300000900
|
|
|
|
|
}, {
|
|
|
|
|
unspent: [0.0001, 0.0003],
|
|
|
|
|
balance: 40000
|
|
|
|
|
}, {
|
|
|
|
|
unspent: [0.0001, 0.0003, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0002],
|
|
|
|
|
balance: 110000
|
|
|
|
|
},
|
2014-06-13 11:30:48 -03:00
|
|
|
|
2014-06-12 17:42:26 -03:00
|
|
|
];
|
2014-06-26 10:47:39 -03:00
|
|
|
var roundWallet = cachedCreateW2();
|
2014-06-12 17:42:26 -03:00
|
|
|
|
2014-06-13 11:30:48 -03:00
|
|
|
roundErrorChecks.forEach(function(c) {
|
2014-06-26 10:47:39 -03:00
|
|
|
it('#getBalance should handle rounding errors: ' + c.unspent[0], function(done) {
|
|
|
|
|
var w = roundWallet;
|
|
|
|
|
//w.generateAddress();
|
2014-06-13 11:30:48 -03:00
|
|
|
w.blockchain.fixUnspent(c.unspent.map(function(u) {
|
|
|
|
|
return {
|
|
|
|
|
amount: u
|
|
|
|
|
}
|
|
|
|
|
}));
|
2014-06-12 17:42:26 -03:00
|
|
|
w.getBalance(function(err, balance, balanceByAddr, safeBalance) {
|
|
|
|
|
balance.should.equal(c.balance);
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
2014-06-09 11:19:38 -03:00
|
|
|
it('should get balance', function(done) {
|
2014-07-31 16:13:27 -03:00
|
|
|
var w = createW2();
|
2014-06-12 17:42:26 -03:00
|
|
|
var spy = sinon.spy(w.blockchain, 'getUnspent');
|
2014-06-24 13:17:22 -03:00
|
|
|
w.blockchain.fixUnspent([]);
|
2014-06-09 11:19:38 -03:00
|
|
|
w.getBalance(function(err, balance, balanceByAddr, safeBalance) {
|
2014-06-12 17:42:26 -03:00
|
|
|
sinon.assert.callCount(spy, 1);
|
2014-06-09 11:19:38 -03:00
|
|
|
balance.should.equal(0);
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
2014-06-09 17:28:56 -03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
// tx handling
|
|
|
|
|
|
|
|
|
|
var createUTXO = function(w) {
|
|
|
|
|
var utxo = [{
|
2014-06-09 11:19:38 -03:00
|
|
|
'txid': '0be0fb4579911be829e3077202e1ab47fcc12cf3ab8f8487ccceae768e1f95fa',
|
|
|
|
|
'vout': 0,
|
|
|
|
|
'ts': 1402323949,
|
|
|
|
|
'amount': 25.0001,
|
|
|
|
|
'confirmations': 10,
|
|
|
|
|
'confirmationsFromCache': false
|
2014-06-09 17:28:56 -03:00
|
|
|
}];
|
2014-11-24 11:46:51 -03:00
|
|
|
sinon.stub(w, 'sendIndexes');
|
2014-06-09 17:28:56 -03:00
|
|
|
var addr = w.generateAddress().toString();
|
2014-11-24 11:46:51 -03:00
|
|
|
w.sendIndexes.restore();
|
|
|
|
|
|
2014-06-09 17:28:56 -03:00
|
|
|
utxo[0].address = addr;
|
2014-07-07 10:35:06 -07:00
|
|
|
utxo[0].scriptPubKey = (new bitcore.Address(addr)).getScriptPubKey().serialize().toString('hex');
|
2014-06-09 17:28:56 -03:00
|
|
|
return utxo;
|
|
|
|
|
};
|
|
|
|
|
var toAddress = 'mjfAe7YrzFujFf8ub5aUrCaN5GfSABdqjh';
|
2014-08-21 16:02:02 -03:00
|
|
|
var amountSatStr = '10000';
|
2014-06-09 17:28:56 -03:00
|
|
|
|
2014-11-24 11:46:51 -03:00
|
|
|
describe('#spend', function() {
|
|
|
|
|
it('should create transaction', function(done) {
|
|
|
|
|
var w = cachedCreateW2();
|
|
|
|
|
var utxo = createUTXO(w);
|
|
|
|
|
w.blockchain.fixUnspent(utxo);
|
|
|
|
|
w.spend({
|
|
|
|
|
toAddress: toAddress,
|
|
|
|
|
amountSat: amountSatStr,
|
|
|
|
|
}, function(err, ntxid) {
|
|
|
|
|
ntxid.length.should.equal(64);
|
|
|
|
|
done();
|
|
|
|
|
});
|
2014-06-09 11:19:38 -03:00
|
|
|
});
|
2014-08-21 16:02:02 -03:00
|
|
|
|
2014-11-24 11:46:51 -03:00
|
|
|
it('should create & sign transaction from received funds', function(done) {
|
|
|
|
|
var k2 = new PrivateKey({
|
|
|
|
|
networkName: walletConfig.networkName
|
|
|
|
|
});
|
2014-08-02 20:51:31 -03:00
|
|
|
|
2014-11-24 11:46:51 -03:00
|
|
|
var w = createW2([k2]);
|
|
|
|
|
var utxo = createUTXO(w);
|
|
|
|
|
w.blockchain.fixUnspent(utxo);
|
2014-11-26 15:15:12 -03:00
|
|
|
var now = Date.now();
|
2014-11-24 11:46:51 -03:00
|
|
|
w.spend({
|
|
|
|
|
toAddress: toAddress,
|
|
|
|
|
amountSat: amountSatStr,
|
|
|
|
|
}, function(err, ntxid) {
|
|
|
|
|
w.on('txProposalsUpdated', function() {
|
2014-11-26 15:15:12 -03:00
|
|
|
var txp = w.txProposals.txps[ntxid];
|
|
|
|
|
var myId = w.getMyCopayerId();
|
|
|
|
|
txp.signedBy[myId].should.be.above(now - 1);
|
|
|
|
|
should.not.exist(txp.rejectedBy[myId]);
|
2014-11-24 11:46:51 -03:00
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
w.privateKey = k2;
|
|
|
|
|
w.sign(ntxid).should.equal.true;
|
2014-06-09 17:28:56 -03:00
|
|
|
});
|
|
|
|
|
});
|
2014-11-24 11:46:51 -03:00
|
|
|
it('should fail to reject a signed transaction', function() {
|
|
|
|
|
var w = cachedCreateW2();
|
|
|
|
|
var utxo = createUTXO(w);
|
|
|
|
|
w.blockchain.fixUnspent(utxo);
|
|
|
|
|
w.spend({
|
|
|
|
|
toAddress: toAddress,
|
|
|
|
|
amountSat: amountSatStr,
|
|
|
|
|
}, function(err, ntxid) {
|
|
|
|
|
(function() {
|
|
|
|
|
w.reject(ntxid);
|
|
|
|
|
}).should.throw('reject a signed');
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should create & reject transaction', function(done) {
|
|
|
|
|
var w = cachedCreateW2();
|
|
|
|
|
var oldK = w.privateKey;
|
|
|
|
|
var utxo = createUTXO(w);
|
|
|
|
|
w.blockchain.fixUnspent(utxo);
|
|
|
|
|
w.spend({
|
|
|
|
|
toAddress: toAddress,
|
|
|
|
|
amountSat: amountSatStr,
|
|
|
|
|
}, function(err, ntxid) {
|
|
|
|
|
var s = sinon.stub(w, 'getMyCopayerId').returns('213');
|
|
|
|
|
Object.keys(w.txProposals.get(ntxid).rejectedBy).length.should.equal(0);
|
2014-08-04 12:43:21 -03:00
|
|
|
w.reject(ntxid);
|
2014-11-24 11:46:51 -03:00
|
|
|
Object.keys(w.txProposals.get(ntxid).rejectedBy).length.should.equal(1);
|
|
|
|
|
w.txProposals.get(ntxid).rejectedBy['213'].should.gt(1);
|
|
|
|
|
s.restore();
|
|
|
|
|
done();
|
|
|
|
|
});
|
2014-08-03 23:57:23 -03:00
|
|
|
});
|
2014-11-24 11:46:51 -03:00
|
|
|
it('should send a TX proposal to peers if incomplete', function(done) {
|
|
|
|
|
var w = createW2(null, 1);
|
|
|
|
|
var utxo = createUTXO(w);
|
|
|
|
|
w.blockchain.fixUnspent(utxo);
|
|
|
|
|
|
|
|
|
|
sinon.spy(w, 'sendIndexes');
|
|
|
|
|
sinon.spy(w, 'sendTxProposal');
|
|
|
|
|
w.spend({
|
|
|
|
|
toAddress: toAddress,
|
|
|
|
|
amountSat: amountSatStr,
|
|
|
|
|
}, function(err, id, status) {
|
2014-11-23 17:41:34 -03:00
|
|
|
should.not.exist(err);
|
2014-11-24 11:46:51 -03:00
|
|
|
should.exist(id);
|
|
|
|
|
status.should.equal(Wallet.TX_PROPOSAL_SENT);
|
|
|
|
|
w.sendTxProposal.calledOnce.should.equal(true);
|
|
|
|
|
w.sendIndexes.calledOnce.should.equal(true);
|
2014-06-09 17:52:08 -03:00
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
2014-11-24 11:46:51 -03:00
|
|
|
it('should broadcast a TX if complete', function(done) {
|
|
|
|
|
var w = createW2(null, 1);
|
|
|
|
|
var utxo = createUTXO(w);
|
|
|
|
|
w.blockchain.fixUnspent(utxo);
|
|
|
|
|
sinon.spy(w, 'sendIndexes');
|
|
|
|
|
sinon.spy(w, 'sendTxProposal');
|
2014-11-27 17:45:10 -03:00
|
|
|
sinon.spy(w, 'issueTx');
|
2014-11-24 11:46:51 -03:00
|
|
|
sinon.stub(w, 'requiresMultipleSignatures').returns(false);
|
2014-11-27 17:45:10 -03:00
|
|
|
sinon.stub(w.blockchain, 'broadcast').yields(null, 1234);
|
2014-11-24 11:46:51 -03:00
|
|
|
w.spend({
|
|
|
|
|
toAddress: toAddress,
|
|
|
|
|
amountSat: amountSatStr,
|
|
|
|
|
}, function(err, id, status) {
|
|
|
|
|
should.not.exist(err);
|
|
|
|
|
should.exist(id);
|
|
|
|
|
status.should.equal(Wallet.TX_BROADCASTED);
|
2014-11-27 17:45:10 -03:00
|
|
|
w.blockchain.broadcast.calledOnce.should.equal(true);
|
|
|
|
|
w.issueTx.calledOnce.should.equal(true);
|
2014-11-24 11:46:51 -03:00
|
|
|
done();
|
2014-09-10 15:09:11 -03:00
|
|
|
});
|
2014-08-27 09:47:45 -03:00
|
|
|
});
|
2014-11-24 11:46:51 -03:00
|
|
|
|
2014-11-25 09:45:44 -03:00
|
|
|
it('should return error if failing to send', function(done) {
|
|
|
|
|
var w = createW2(null, 1);
|
|
|
|
|
var utxo = createUTXO(w);
|
|
|
|
|
w.blockchain.fixUnspent(utxo);
|
|
|
|
|
sinon.stub(w, 'requiresMultipleSignatures').returns(false);
|
|
|
|
|
sinon.spy(w, 'sendIndexes');
|
|
|
|
|
sinon.spy(w, 'sendTxProposal');
|
2014-11-27 17:45:10 -03:00
|
|
|
sinon.stub(w, 'broadcastToBitcoinNetwork').yields('error');
|
2014-11-25 09:45:44 -03:00
|
|
|
w.spend({
|
|
|
|
|
toAddress: toAddress,
|
|
|
|
|
amountSat: amountSatStr,
|
|
|
|
|
}, function(err, id, status) {
|
|
|
|
|
err.should.equal('error');
|
|
|
|
|
w.sendTxProposal.calledOnce.should.equal(false);
|
|
|
|
|
w.sendIndexes.calledOnce.should.equal(true);
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
it('should send TxProposal', function(done) {
|
|
|
|
|
var w = cachedCreateW2();
|
|
|
|
|
var utxo = createUTXO(w);
|
|
|
|
|
w.blockchain.fixUnspent(utxo);
|
|
|
|
|
w.spend({
|
|
|
|
|
toAddress: toAddress,
|
|
|
|
|
amountSat: amountSatStr,
|
|
|
|
|
}, function(err, ntxid) {
|
|
|
|
|
w.sendTxProposal.bind(w).should.throw('Illegal Argument.');
|
|
|
|
|
(function() {
|
|
|
|
|
w.sendTxProposal(ntxid);
|
|
|
|
|
}).should.not.throw();
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should send all TxProposal', function(done) {
|
|
|
|
|
var w = cachedCreateW2();
|
|
|
|
|
var utxo = createUTXO(w);
|
|
|
|
|
w.blockchain.fixUnspent(utxo);
|
|
|
|
|
w.spend({
|
|
|
|
|
toAddress: toAddress,
|
|
|
|
|
amountSat: amountSatStr,
|
|
|
|
|
}, function(err, ntxid) {
|
|
|
|
|
w.sendAllTxProposals.bind(w).should.not.throw();
|
|
|
|
|
(function() {
|
|
|
|
|
w.sendAllTxProposals();
|
|
|
|
|
}).should.not.throw();
|
|
|
|
|
done();
|
|
|
|
|
});
|
2014-08-27 10:36:01 -03:00
|
|
|
});
|
2014-11-25 09:45:44 -03:00
|
|
|
|
|
|
|
|
|
2014-08-27 10:36:01 -03:00
|
|
|
});
|
2014-11-27 17:45:10 -03:00
|
|
|
describe('#issueTx', function() {
|
2014-11-25 10:59:49 -03:00
|
|
|
it('should broadcast a TX', function(done) {
|
2014-11-25 09:45:44 -03:00
|
|
|
var w = createW2(null, 1);
|
|
|
|
|
var utxo = createUTXO(w);
|
2014-11-27 18:26:05 -03:00
|
|
|
var now = Date.now();
|
2014-11-25 10:59:49 -03:00
|
|
|
var txp = w._createTxProposal(PP.outs[0].address, PP.outs[0].amountSatStr, 'hola', utxo);
|
2014-11-25 09:45:44 -03:00
|
|
|
var ntxid = w.txProposals.add(txp);
|
2014-11-25 10:59:49 -03:00
|
|
|
sinon.stub(w.blockchain, 'broadcast').yields(null, 1234);
|
2014-11-25 09:45:44 -03:00
|
|
|
|
2014-11-27 17:45:10 -03:00
|
|
|
w.issueTx(ntxid, function(err, txid, status) {
|
2014-11-25 09:45:44 -03:00
|
|
|
should.not.exist(err);
|
2014-11-28 18:43:22 -03:00
|
|
|
txp.getSent().should.be.above(now - 1);
|
2014-11-27 18:26:05 -03:00
|
|
|
txp.sentTxid.should.be.equal(txid);
|
2014-11-25 09:45:44 -03:00
|
|
|
txid.should.equal(1234);
|
|
|
|
|
status.should.equal(Wallet.TX_BROADCASTED);
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
2014-11-25 17:44:51 -03:00
|
|
|
|
2014-11-25 10:59:49 -03:00
|
|
|
it('should send Payment Messages on a PayPro payment', function(done) {
|
2014-11-25 09:45:44 -03:00
|
|
|
var w = createW2(null, 1);
|
|
|
|
|
var utxo = createUTXO(w);
|
2014-11-25 10:59:49 -03:00
|
|
|
var txp = w._createTxProposal(PP.outs[0].address, PP.outs[0].amountSatStr, 'hola', utxo);
|
|
|
|
|
txp.paymentProtocolURL = PP.merchant_data.request_url;
|
|
|
|
|
txp.addMerchantData(PP.merchant_data);
|
2014-11-25 09:45:44 -03:00
|
|
|
var ntxid = w.txProposals.add(txp);
|
2014-11-25 10:59:49 -03:00
|
|
|
var success = sinon.stub().yields('paymentACK123').returns({
|
|
|
|
|
error: sinon.stub(),
|
|
|
|
|
});
|
2014-11-25 09:45:44 -03:00
|
|
|
|
|
|
|
|
sinon.stub(w.blockchain, 'broadcast').yields(null, 1234);
|
2014-11-25 10:59:49 -03:00
|
|
|
sinon.stub(w.httpUtil, 'request').returns({
|
|
|
|
|
success: success,
|
|
|
|
|
});
|
|
|
|
|
sinon.stub(w, 'onPayProPaymentAck');
|
|
|
|
|
|
|
|
|
|
|
2014-11-27 17:45:10 -03:00
|
|
|
w.issueTx(ntxid, function(err, txid, status) {
|
2014-11-25 09:45:44 -03:00
|
|
|
should.not.exist(err);
|
|
|
|
|
txid.should.equal(1234);
|
|
|
|
|
status.should.equal(Wallet.TX_BROADCASTED);
|
2014-11-25 10:59:49 -03:00
|
|
|
w.httpUtil.request.calledOnce.should.equal(true);
|
|
|
|
|
w.httpUtil.request.getCall(0).args[0].url.should.equal('url123');
|
|
|
|
|
success.calledOnce.should.equal(true);
|
|
|
|
|
w.onPayProPaymentAck.calledOnce.should.equal(true);
|
|
|
|
|
w.onPayProPaymentAck.getCall(0).args[1].should.equal('paymentACK123');
|
2014-11-25 09:45:44 -03:00
|
|
|
done();
|
|
|
|
|
});
|
2014-06-18 10:09:40 -03:00
|
|
|
});
|
2014-11-27 17:45:10 -03:00
|
|
|
|
|
|
|
|
it('should fail to send incomplete transaction', function(done) {
|
|
|
|
|
var w = createW2(null, 1);
|
|
|
|
|
var utxo = createUTXO(w);
|
|
|
|
|
var txp = w._createTxProposal(toAddress, amountSatStr + 0, 'hola', utxo);
|
|
|
|
|
var ntxid = w.txProposals.add(txp);
|
|
|
|
|
|
|
|
|
|
// Assign fake builder
|
|
|
|
|
sinon.stub(txp.builder, 'build').returns({
|
|
|
|
|
serialize: sinon.stub().returns('xxx'),
|
|
|
|
|
isComplete: sinon.stub().returns(false),
|
|
|
|
|
});
|
|
|
|
|
(function() {
|
|
|
|
|
w.issueTx(ntxid);
|
|
|
|
|
}).should.throw('tx is not complete');
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-06-09 18:01:15 -03:00
|
|
|
});
|
2014-06-13 11:30:48 -03:00
|
|
|
|
2014-11-23 00:29:50 -03:00
|
|
|
|
|
|
|
|
describe('#fetchPaymentRequest', function() {
|
|
|
|
|
it('should fetch a payment request', function(done) {
|
|
|
|
|
var w = cachedCreateW2();
|
|
|
|
|
sinon.stub(w, 'parsePaymentRequest').returns({
|
|
|
|
|
hola: 1
|
|
|
|
|
});
|
|
|
|
|
var opts = {
|
|
|
|
|
a: 1,
|
|
|
|
|
url: 'http://xxx',
|
|
|
|
|
};
|
|
|
|
|
|
2014-11-24 11:46:51 -03:00
|
|
|
var rawData = 'wqer';
|
2014-11-23 00:29:50 -03:00
|
|
|
var e = sinon.stub();
|
|
|
|
|
e.error = sinon.stub();
|
|
|
|
|
|
|
|
|
|
var s = sinon.stub();
|
|
|
|
|
s.success = sinon.stub().yields(rawData).returns(e);
|
|
|
|
|
|
2014-11-24 11:46:51 -03:00
|
|
|
sinon.stub(w.httpUtil, 'request').returns(s);
|
2014-11-23 00:29:50 -03:00
|
|
|
|
2014-11-24 11:46:51 -03:00
|
|
|
w.fetchPaymentRequest(opts, function(err, merchantData) {
|
2014-11-23 00:29:50 -03:00
|
|
|
should.not.exist(err);
|
|
|
|
|
should.exist(merchantData);
|
2014-11-24 11:46:51 -03:00
|
|
|
w.parsePaymentRequest.firstCall.args.should.deep.equal([opts, rawData]);
|
2014-11-23 00:29:50 -03:00
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should return error on fetch error', function(done) {
|
|
|
|
|
var w = cachedCreateW2();
|
|
|
|
|
var opts = {
|
|
|
|
|
a: 1,
|
|
|
|
|
url: 'http://xxx',
|
|
|
|
|
};
|
|
|
|
|
|
2014-11-24 11:46:51 -03:00
|
|
|
var rawData = 'wqer';
|
2014-11-23 00:29:50 -03:00
|
|
|
var e = sinon.stub();
|
|
|
|
|
e.error = sinon.stub().yields(null, 'status');
|
|
|
|
|
|
|
|
|
|
var s = sinon.stub();
|
|
|
|
|
s.success = sinon.stub().returns(e);
|
2014-11-24 11:46:51 -03:00
|
|
|
sinon.stub(w.httpUtil, 'request').returns(s);
|
|
|
|
|
w.fetchPaymentRequest(opts, function(err, merchantData) {
|
2014-11-23 00:29:50 -03:00
|
|
|
err.toString().should.contain('status');
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// TODO parsePaymentRequest should have more tests,
|
2014-11-25 10:59:49 -03:00
|
|
|
// PP.getRequest should be parametrizable
|
2014-11-23 00:29:50 -03:00
|
|
|
describe('#parsePaymentRequest', function() {
|
|
|
|
|
it('should parse a Payment Request', function() {
|
2014-11-24 11:46:51 -03:00
|
|
|
var now = Date.now() / 1000;
|
2014-11-23 00:29:50 -03:00
|
|
|
var w = cachedCreateW2();
|
|
|
|
|
var opts = {
|
|
|
|
|
url: 'http://xxx',
|
|
|
|
|
};
|
2014-11-25 10:59:49 -03:00
|
|
|
var data = PP.getRequest();
|
2014-11-24 11:46:51 -03:00
|
|
|
var md = w.parsePaymentRequest(opts, data);
|
2014-11-25 10:59:49 -03:00
|
|
|
md.outs.should.deep.equal(PP.outs);
|
2014-11-23 00:29:50 -03:00
|
|
|
md.request_url.should.equal(opts.url);
|
|
|
|
|
md.pr.untrusted.should.equal(true);
|
|
|
|
|
md.expires.should.be.above(now);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2014-11-23 17:41:34 -03:00
|
|
|
describe('#spend', function() {
|
2014-09-10 15:09:11 -03:00
|
|
|
it('should fail if insight server is down', function(done) {
|
2014-09-08 16:37:33 -03:00
|
|
|
var w = cachedCreateW2();
|
|
|
|
|
var utxo = createUTXO(w);
|
|
|
|
|
sinon.stub(w, 'getUnspent').yields('error', null);
|
2014-11-23 17:41:34 -03:00
|
|
|
w.spend({
|
2014-11-22 20:00:18 -03:00
|
|
|
toAddress: toAddress,
|
|
|
|
|
amountSat: amountSatStr,
|
|
|
|
|
}, function(err, ntxid) {
|
2014-11-23 00:29:50 -03:00
|
|
|
err.message.should.contain('UTXOs');
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
it('should fail with broken PayPro', function(done) {
|
|
|
|
|
var w = cachedCreateW2();
|
|
|
|
|
var utxo = createUTXO(w);
|
|
|
|
|
w.blockchain.fixUnspent(utxo);
|
|
|
|
|
sinon.stub(w, 'fetchPaymentRequest').yields('error');
|
2014-11-23 17:41:34 -03:00
|
|
|
w.spend({
|
2014-11-23 00:29:50 -03:00
|
|
|
url: 'test',
|
|
|
|
|
}, function(err, ntxid) {
|
|
|
|
|
should.exist(err);
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
it('should create a TX with PayPro', function(done) {
|
|
|
|
|
var w = cachedCreateW2();
|
|
|
|
|
var utxo = createUTXO(w);
|
|
|
|
|
w.blockchain.fixUnspent(utxo);
|
|
|
|
|
sinon.stub(w, 'fetchPaymentRequest').yields(null, {
|
|
|
|
|
outs: [{
|
|
|
|
|
address: 'n2Wz7KjyzBJVaNMBN88Lj1YUHMDZSAGeMV',
|
|
|
|
|
amountSatStr: '123400',
|
|
|
|
|
}],
|
|
|
|
|
request_url: 'url',
|
|
|
|
|
pr: {
|
|
|
|
|
signature: '123',
|
|
|
|
|
},
|
|
|
|
|
total: '123400',
|
|
|
|
|
});
|
2014-11-23 17:41:34 -03:00
|
|
|
w.spend({
|
2014-11-23 00:29:50 -03:00
|
|
|
url: 'test',
|
|
|
|
|
}, function(err, ntxid) {
|
|
|
|
|
should.not.exist(err);
|
2014-09-10 15:09:11 -03:00
|
|
|
done();
|
2014-09-08 16:37:33 -03:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2014-11-26 15:15:12 -03:00
|
|
|
describe.skip('removeTxWithSpentInputs', function() {
|
2014-09-29 17:36:34 -03:00
|
|
|
var w;
|
|
|
|
|
var utxos;
|
|
|
|
|
beforeEach(function() {
|
|
|
|
|
w = cachedCreateW2();
|
|
|
|
|
w.txProposals.deleteOne = sinon.spy();
|
|
|
|
|
utxos = [{
|
|
|
|
|
txid: 'txid0',
|
|
|
|
|
vout: 'vout1',
|
|
|
|
|
}, {
|
|
|
|
|
txid: 'txid0',
|
|
|
|
|
vout: 'vout2',
|
|
|
|
|
}];
|
|
|
|
|
});
|
2014-09-04 17:37:38 -03:00
|
|
|
it('should remove pending TxProposal with spent inputs', function(done) {
|
2014-09-29 17:36:34 -03:00
|
|
|
var txp = {
|
|
|
|
|
ntxid: 'txid1',
|
|
|
|
|
isPending: true,
|
|
|
|
|
builder: {
|
|
|
|
|
utxos: [utxos[0]],
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
w.getTxProposals = sinon.stub().returns([txp]);
|
|
|
|
|
w.blockchain.getUnspent = sinon.stub().yields(null, utxos);
|
|
|
|
|
w.removeTxWithSpentInputs(function() {
|
|
|
|
|
w.txProposals.deleteOne.called.should.be.false;
|
|
|
|
|
w.blockchain.getUnspent = sinon.stub().yields(null, []);
|
|
|
|
|
w.removeTxWithSpentInputs(function() {
|
|
|
|
|
w.txProposals.deleteOne.calledWith('txid1').should.be.true;
|
|
|
|
|
done();
|
|
|
|
|
});
|
2014-08-27 16:42:52 -03:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2014-09-04 17:37:38 -03:00
|
|
|
it('should remove pending TxProposal with at least 1 spent input', function(done) {
|
2014-09-29 17:36:34 -03:00
|
|
|
var txp = {
|
|
|
|
|
ntxid: 'txid1',
|
|
|
|
|
isPending: true,
|
|
|
|
|
builder: {
|
|
|
|
|
utxos: utxos,
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
w.getTxProposals = sinon.stub().returns([txp]);
|
|
|
|
|
w.blockchain.getUnspent = sinon.stub().yields(null, utxos);
|
|
|
|
|
w.removeTxWithSpentInputs(function() {
|
|
|
|
|
w.txProposals.deleteOne.called.should.be.false;
|
|
|
|
|
w.blockchain.getUnspent = sinon.stub().yields(null, [utxos[0]]);
|
|
|
|
|
w.removeTxWithSpentInputs(function() {
|
|
|
|
|
w.txProposals.deleteOne.calledWith('txid1').should.be.true;
|
|
|
|
|
done();
|
|
|
|
|
});
|
2014-08-27 16:42:52 -03:00
|
|
|
});
|
|
|
|
|
});
|
2014-09-04 17:37:38 -03:00
|
|
|
|
|
|
|
|
it('should not remove complete TxProposal', function(done) {
|
2014-09-29 17:36:34 -03:00
|
|
|
var txp = {
|
|
|
|
|
ntxid: 'txid1',
|
|
|
|
|
isPending: false,
|
|
|
|
|
builder: {
|
|
|
|
|
utxos: [utxos[0]],
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
w.getTxProposals = sinon.stub().returns([txp]);
|
|
|
|
|
w.blockchain.getUnspent = sinon.stub().yields(null, utxos);
|
|
|
|
|
w.removeTxWithSpentInputs(function() {
|
|
|
|
|
w.txProposals.deleteOne.called.should.be.false;
|
|
|
|
|
w.blockchain.getUnspent = sinon.stub().yields(null, []);
|
|
|
|
|
w.removeTxWithSpentInputs(function() {
|
|
|
|
|
w.txProposals.deleteOne.called.should.be.false;
|
|
|
|
|
done();
|
|
|
|
|
});
|
2014-09-04 17:37:38 -03:00
|
|
|
});
|
|
|
|
|
});
|
2014-08-27 16:42:52 -03:00
|
|
|
});
|
|
|
|
|
|
2014-09-10 18:03:31 -03:00
|
|
|
describe('#subscribeToAddresses', function() {
|
|
|
|
|
it('should subscribe successfully', function() {
|
|
|
|
|
var w = cachedCreateW2();
|
|
|
|
|
var addr2 = w.generateAddress().toString();
|
|
|
|
|
var addr3 = w.generateAddress(true).toString();
|
|
|
|
|
|
|
|
|
|
w.blockchain.subscribe = sinon.spy();
|
|
|
|
|
w.subscribeToAddresses();
|
|
|
|
|
w.blockchain.subscribe.calledOnce.should.equal(true);
|
|
|
|
|
var arg = w.blockchain.subscribe.getCall(0).args[0];
|
2014-11-28 18:43:22 -03:00
|
|
|
_.intersection(arg, [addr2, addr3]).length.should.be.equal(2);
|
2014-09-10 18:03:31 -03:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2014-11-03 15:47:35 -03:00
|
|
|
describe('#estimatedFee', function() {
|
|
|
|
|
it('should calculate estimated fee', function() {
|
|
|
|
|
var COIN = 100000000;
|
|
|
|
|
Wallet.estimatedFee(1).should.equal(0.0001 * COIN);
|
|
|
|
|
Wallet.estimatedFee(2).should.equal(0.0001 * COIN);
|
|
|
|
|
Wallet.estimatedFee(3).should.equal(0.0002 * COIN);
|
|
|
|
|
Wallet.estimatedFee(1000).should.equal(0.0245 * COIN);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-11-23 17:41:34 -03:00
|
|
|
describe('#_sendToPeers', function() {
|
2014-07-24 21:18:38 -03:00
|
|
|
it('should call this.network.send', function() {
|
2014-07-08 23:03:30 -07:00
|
|
|
var w = cachedCreateW2();
|
|
|
|
|
var save = w.network.send;
|
|
|
|
|
w.network.send = sinon.spy();
|
2014-11-24 11:46:51 -03:00
|
|
|
w._sendToPeers(null, {
|
|
|
|
|
type: 'hola'
|
|
|
|
|
});
|
2014-07-08 23:03:30 -07:00
|
|
|
w.network.send.calledOnce.should.equal(true);
|
|
|
|
|
w.network.send = save;
|
|
|
|
|
});
|
|
|
|
|
});
|
2014-06-25 13:06:25 -03:00
|
|
|
|
|
|
|
|
describe('#indexDiscovery', function() {
|
|
|
|
|
var ADDRESSES_CHANGE, ADDRESSES_RECEIVE, w;
|
|
|
|
|
|
|
|
|
|
before(function() {
|
|
|
|
|
w = cachedCreateW2();
|
2014-07-03 16:42:03 -03:00
|
|
|
ADDRESSES_CHANGE = w.deriveAddresses(0, 20, true, 0);
|
|
|
|
|
ADDRESSES_RECEIVE = w.deriveAddresses(0, 20, false, 0);
|
2014-06-25 13:06:25 -03:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
var mockFakeActivity = function(f) {
|
2014-08-28 14:23:49 -03:00
|
|
|
w.blockchain.getActivity = function(addresses, cb) {
|
2014-06-25 13:06:25 -03:00
|
|
|
var activity = new Array(addresses.length);
|
|
|
|
|
for (var i = 0; i < addresses.length; i++) {
|
|
|
|
|
var a1 = ADDRESSES_CHANGE.indexOf(addresses[i]);
|
|
|
|
|
var a2 = ADDRESSES_RECEIVE.indexOf(addresses[i]);
|
|
|
|
|
activity[i] = f(Math.max(a1, a2));
|
|
|
|
|
}
|
|
|
|
|
cb(null, activity);
|
2014-06-18 14:24:48 -03:00
|
|
|
}
|
2014-06-18 10:58:34 -03:00
|
|
|
}
|
|
|
|
|
|
2014-06-25 13:06:25 -03:00
|
|
|
it('#indexDiscovery should work without found activities', function(done) {
|
|
|
|
|
mockFakeActivity(function(index) {
|
|
|
|
|
return false;
|
|
|
|
|
});
|
2014-07-03 16:42:03 -03:00
|
|
|
w.indexDiscovery(0, false, 0, 5, function(e, lastActive) {
|
2014-06-25 13:06:25 -03:00
|
|
|
lastActive.should.equal(-1);
|
|
|
|
|
done();
|
|
|
|
|
});
|
2014-06-18 10:58:34 -03:00
|
|
|
});
|
|
|
|
|
|
2014-06-25 13:06:25 -03:00
|
|
|
it('#indexDiscovery should continue scanning', function(done) {
|
|
|
|
|
mockFakeActivity(function(index) {
|
|
|
|
|
return index <= 7;
|
|
|
|
|
});
|
2014-07-03 16:42:03 -03:00
|
|
|
w.indexDiscovery(0, false, 0, 5, function(e, lastActive) {
|
2014-06-25 13:06:25 -03:00
|
|
|
lastActive.should.equal(7);
|
|
|
|
|
done();
|
|
|
|
|
});
|
2014-06-18 10:58:34 -03:00
|
|
|
});
|
|
|
|
|
|
2014-06-25 13:06:25 -03:00
|
|
|
it('#indexDiscovery should not found beyond the scannWindow', function(done) {
|
|
|
|
|
mockFakeActivity(function(index) {
|
|
|
|
|
return index <= 10 || index == 17;
|
|
|
|
|
});
|
2014-07-03 16:42:03 -03:00
|
|
|
w.indexDiscovery(0, false, 0, 5, function(e, lastActive) {
|
2014-06-25 13:06:25 -03:00
|
|
|
lastActive.should.equal(10);
|
|
|
|
|
done();
|
|
|
|
|
});
|
2014-06-18 10:58:34 -03:00
|
|
|
});
|
|
|
|
|
|
2014-06-25 13:06:25 -03:00
|
|
|
it('#indexDiscovery should look for activity along the scannWindow', function(done) {
|
|
|
|
|
mockFakeActivity(function(index) {
|
|
|
|
|
return index <= 14 && index % 2 == 0;
|
|
|
|
|
});
|
2014-07-03 16:42:03 -03:00
|
|
|
w.indexDiscovery(0, false, 0, 5, function(e, lastActive) {
|
2014-06-25 13:06:25 -03:00
|
|
|
lastActive.should.equal(14);
|
|
|
|
|
done();
|
|
|
|
|
});
|
2014-06-18 10:58:34 -03:00
|
|
|
});
|
2014-06-18 14:24:48 -03:00
|
|
|
|
2014-06-25 13:06:25 -03:00
|
|
|
it('#updateIndexes should update correctly', function(done) {
|
|
|
|
|
mockFakeActivity(function(index) {
|
|
|
|
|
return index <= 14 && index % 2 == 0;
|
|
|
|
|
});
|
2014-06-18 14:24:48 -03:00
|
|
|
|
2014-07-24 21:18:38 -03:00
|
|
|
var updateIndex = sinon.stub(w, 'updateIndex', function(i, cb) {
|
|
|
|
|
cb();
|
|
|
|
|
});
|
2014-07-10 16:19:09 -03:00
|
|
|
|
2014-06-25 13:06:25 -03:00
|
|
|
w.updateIndexes(function(err) {
|
2014-07-10 16:19:09 -03:00
|
|
|
// check updated all indexes
|
|
|
|
|
var cosignersChecked = []
|
2014-07-24 21:18:38 -03:00
|
|
|
updateIndex.args.forEach(function(i) {
|
2014-07-29 13:09:47 -03:00
|
|
|
cosignersChecked.indexOf(i[0].copayerIndex).should.equal(-1);
|
|
|
|
|
cosignersChecked.push(i[0].copayerIndex);
|
2014-07-10 16:19:09 -03:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
sinon.assert.callCount(updateIndex, 4);
|
2014-08-22 14:44:40 -04:00
|
|
|
sinon.assert.calledWith(updateIndex, w.publicKeyRing.indexes[0]);
|
|
|
|
|
sinon.assert.calledWith(updateIndex, w.publicKeyRing.indexes[1]);
|
|
|
|
|
sinon.assert.calledWith(updateIndex, w.publicKeyRing.indexes[2]);
|
2014-07-10 16:19:09 -03:00
|
|
|
w.updateIndex.restore();
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
2014-07-03 16:42:03 -03:00
|
|
|
|
2014-07-10 16:19:09 -03:00
|
|
|
it('#updateIndex should update correctly', function(done) {
|
|
|
|
|
mockFakeActivity(function(index) {
|
|
|
|
|
return index <= 14 && index % 2 == 0;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
2014-07-24 21:18:38 -03:00
|
|
|
var indexDiscovery = sinon.stub(w, 'indexDiscovery', function(a, b, c, d, cb) {
|
|
|
|
|
cb(null, 8);
|
|
|
|
|
});
|
2014-07-10 16:19:09 -03:00
|
|
|
var index = {
|
|
|
|
|
changeIndex: 1,
|
|
|
|
|
receiveIndex: 2,
|
2014-07-29 13:09:47 -03:00
|
|
|
copayerIndex: 2,
|
2014-07-10 16:19:09 -03:00
|
|
|
}
|
|
|
|
|
w.updateIndex(index, function(err) {
|
|
|
|
|
index.receiveIndex.should.equal(9);
|
|
|
|
|
index.changeIndex.should.equal(9);
|
|
|
|
|
indexDiscovery.callCount.should.equal(2);
|
2014-08-22 14:44:40 -04:00
|
|
|
sinon.assert.calledWith(indexDiscovery, 1, true, 2, 20);
|
|
|
|
|
sinon.assert.calledWith(indexDiscovery, 2, false, 2, 20);
|
2014-07-10 16:19:09 -03:00
|
|
|
w.indexDiscovery.restore();
|
2014-06-25 13:06:25 -03:00
|
|
|
done();
|
|
|
|
|
});
|
2014-06-23 10:59:33 -03:00
|
|
|
});
|
2014-06-25 13:06:25 -03:00
|
|
|
|
2014-07-10 16:19:09 -03:00
|
|
|
|
2014-11-12 13:46:55 -03:00
|
|
|
it.skip('#updateIndexes should store wallet', function(done) {
|
2014-06-25 13:06:25 -03:00
|
|
|
mockFakeActivity(function(index) {
|
|
|
|
|
return index <= 14 && index % 2 == 0;
|
|
|
|
|
});
|
2014-07-24 21:18:38 -03:00
|
|
|
var indexDiscovery = sinon.stub(w, 'indexDiscovery', function(a, b, c, d, cb) {
|
|
|
|
|
cb(null, 8);
|
|
|
|
|
});
|
2014-10-27 13:13:08 -03:00
|
|
|
var spyStore = sinon.spy(w, 'emitAndKeepAlive');
|
2014-06-25 13:06:25 -03:00
|
|
|
w.updateIndexes(function(err) {
|
|
|
|
|
sinon.assert.callCount(spyStore, 1);
|
|
|
|
|
done();
|
|
|
|
|
});
|
2014-06-18 14:24:48 -03:00
|
|
|
});
|
2014-06-25 13:06:25 -03:00
|
|
|
|
2014-06-18 14:24:48 -03:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('#deriveAddresses', function(done) {
|
2014-06-24 17:48:05 -07:00
|
|
|
var w = cachedCreateW2();
|
2014-07-03 16:42:03 -03:00
|
|
|
var addresses1 = w.deriveAddresses(0, 5, false, 0);
|
|
|
|
|
var addresses2 = w.deriveAddresses(4, 5, false, 0);
|
2014-06-18 14:24:48 -03:00
|
|
|
|
|
|
|
|
addresses1.length.should.equal(5);
|
|
|
|
|
addresses2.length.should.equal(5);
|
|
|
|
|
|
|
|
|
|
addresses1[4].should.equal(addresses2[0]);
|
|
|
|
|
done();
|
2014-06-09 18:01:15 -03:00
|
|
|
});
|
2014-06-13 11:30:48 -03:00
|
|
|
|
2014-07-07 01:33:39 -03:00
|
|
|
describe('#AddressBook', function() {
|
|
|
|
|
var contacts = [{
|
|
|
|
|
label: 'Charles',
|
|
|
|
|
address: '2N8pJWpXCAxmNLHKVEhz3TtTcYCtHd43xWU ',
|
|
|
|
|
}, {
|
|
|
|
|
label: 'Linda',
|
|
|
|
|
address: '2N4Zq92goYGrf5J4F4SZZq7jnPYbCiyRYT2 ',
|
|
|
|
|
}];
|
2014-06-18 01:00:32 -03:00
|
|
|
|
2014-07-07 01:33:39 -03:00
|
|
|
it('should create new entry for address book', function() {
|
|
|
|
|
var w = createW();
|
|
|
|
|
contacts.forEach(function(c) {
|
|
|
|
|
w.setAddressBook(c.address, c.label);
|
|
|
|
|
});
|
|
|
|
|
Object.keys(w.addressBook).length.should.equal(4);
|
2014-06-18 01:00:32 -03:00
|
|
|
});
|
|
|
|
|
|
2014-07-07 01:33:39 -03:00
|
|
|
it('should fail if create a duplicate address', function() {
|
|
|
|
|
var w = createW();
|
2014-06-18 20:18:13 -03:00
|
|
|
w.setAddressBook(contacts[0].address, contacts[0].label);
|
2014-07-07 01:33:39 -03:00
|
|
|
(function() {
|
|
|
|
|
w.setAddressBook(contacts[0].address, contacts[0].label);
|
|
|
|
|
}).should.
|
2014-08-22 14:44:40 -04:00
|
|
|
throw();
|
2014-07-07 01:33:39 -03:00
|
|
|
});
|
2014-06-23 10:59:33 -03:00
|
|
|
|
2014-07-07 01:33:39 -03:00
|
|
|
it('should show/hide everywhere', function() {
|
|
|
|
|
var w = createW();
|
|
|
|
|
var key = '2NFR2kzH9NUdp8vsXTB4wWQtTtzhpKxsyoJ';
|
|
|
|
|
w.toggleAddressBookEntry(key);
|
|
|
|
|
w.addressBook[key].hidden.should.equal(true);
|
|
|
|
|
w.toggleAddressBookEntry(key);
|
|
|
|
|
w.addressBook[key].hidden.should.equal(false);
|
2014-07-24 21:18:38 -03:00
|
|
|
(function() {
|
2014-07-07 10:58:43 -03:00
|
|
|
w.toggleAddressBookEntry();
|
|
|
|
|
}).should.throw();
|
2014-07-07 01:33:39 -03:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('handle network addressBook correctly', function() {
|
|
|
|
|
var w = createW();
|
2014-07-07 19:12:34 -03:00
|
|
|
|
2014-07-07 01:33:39 -03:00
|
|
|
var data = {
|
2014-07-24 21:18:38 -03:00
|
|
|
type: "addressbook",
|
2014-07-07 01:33:39 -03:00
|
|
|
addressBook: {
|
2014-07-24 21:18:38 -03:00
|
|
|
"3Ae1ieAYNXznm7NkowoFTu5MkzgrTfDz8Z": {
|
2014-07-07 19:12:34 -03:00
|
|
|
copayerId: "03baa45498fee1045fa8f91a2913f638dc3979b455498924d3cf1a11303c679cdb",
|
|
|
|
|
createdTs: 1404769393509,
|
|
|
|
|
hidden: false,
|
|
|
|
|
label: "adsf",
|
2014-11-23 10:45:11 -03:00
|
|
|
dummy: 'foo',
|
2014-07-07 01:33:39 -03:00
|
|
|
}
|
2014-07-24 21:18:38 -03:00
|
|
|
},
|
|
|
|
|
walletId: "11d23e638ed84c06",
|
2014-07-07 19:12:34 -03:00
|
|
|
isBroadcast: 1
|
2014-07-07 17:38:17 -03:00
|
|
|
};
|
2014-07-07 19:12:34 -03:00
|
|
|
|
|
|
|
|
var senderId = "03baa45498fee1045fa8f91a2913f638dc3979b455498924d3cf1a11303c679cdb";
|
2014-07-24 21:18:38 -03:00
|
|
|
|
2014-07-07 01:33:39 -03:00
|
|
|
Object.keys(w.addressBook).length.should.equal(2);
|
2014-08-19 12:51:55 -04:00
|
|
|
w._onAddressBook(senderId, data, true);
|
2014-07-07 01:33:39 -03:00
|
|
|
Object.keys(w.addressBook).length.should.equal(3);
|
2014-11-23 10:45:11 -03:00
|
|
|
should.exist(w.addressBook['3Ae1ieAYNXznm7NkowoFTu5MkzgrTfDz8Z'].createdTs);
|
|
|
|
|
should.not.exist(w.addressBook['3Ae1ieAYNXznm7NkowoFTu5MkzgrTfDz8Z'].dummy);
|
2014-07-24 21:18:38 -03:00
|
|
|
});
|
2014-06-19 14:21:38 -03:00
|
|
|
});
|
|
|
|
|
|
2014-06-19 11:03:31 -07:00
|
|
|
it('#getNetworkName', function() {
|
|
|
|
|
var w = createW();
|
|
|
|
|
w.getNetworkName().should.equal('testnet');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe('#getMyCopayerId', function() {
|
|
|
|
|
it('should call getCopayerId', function() {
|
2014-06-24 17:48:05 -07:00
|
|
|
var w = cachedCreateW2();
|
2014-06-19 11:03:31 -07:00
|
|
|
w.getCopayerId = sinon.spy();
|
|
|
|
|
w.getMyCopayerId();
|
|
|
|
|
w.getCopayerId.calledOnce.should.equal(true);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe('#getMyCopayerIdPriv', function() {
|
|
|
|
|
it('should call privateKey.getIdPriv', function() {
|
2014-06-24 17:48:05 -07:00
|
|
|
var w = cachedCreateW2();
|
2014-06-19 11:03:31 -07:00
|
|
|
w.privateKey.getIdPriv = sinon.spy();
|
|
|
|
|
w.getMyCopayerIdPriv();
|
|
|
|
|
w.privateKey.getIdPriv.calledOnce.should.equal(true);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2014-09-12 10:40:47 -03:00
|
|
|
describe('#getMyCopayerNickname', function() {
|
|
|
|
|
it('should call publicKeyRing.nicknameForCopayer', function() {
|
|
|
|
|
var w = cachedCreateW2();
|
|
|
|
|
w.publicKeyRing.nicknameForCopayer = sinon.spy();
|
|
|
|
|
w.getMyCopayerNickname();
|
|
|
|
|
w.publicKeyRing.nicknameForCopayer.calledOnce.should.equal(true);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2014-06-19 11:03:31 -07:00
|
|
|
describe('#netStart', function() {
|
|
|
|
|
it('should call Network.start', function() {
|
2014-06-24 17:48:05 -07:00
|
|
|
var w = cachedCreateW2();
|
2014-06-19 11:03:31 -07:00
|
|
|
w.network.start = sinon.spy();
|
|
|
|
|
w.netStart();
|
|
|
|
|
w.network.start.calledOnce.should.equal(true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should call Network.start with a private key', function() {
|
2014-06-24 17:48:05 -07:00
|
|
|
var w = cachedCreateW2();
|
2014-06-19 11:03:31 -07:00
|
|
|
w.network.start = sinon.spy();
|
|
|
|
|
w.netStart();
|
|
|
|
|
w.network.start.getCall(0).args[0].privkey.length.should.equal(64);
|
|
|
|
|
});
|
2014-08-07 20:07:41 -03:00
|
|
|
|
2014-11-12 18:34:49 -03:00
|
|
|
it('should call subscribeToAddresses', function() {
|
|
|
|
|
var w = cachedCreateW2();
|
|
|
|
|
|
|
|
|
|
w.blockchain.on = sinon.stub();
|
|
|
|
|
w.subscribeToAddresses = sinon.spy();
|
|
|
|
|
w.netStart();
|
|
|
|
|
w.subscribeToAddresses.calledOnce.should.equal(true);
|
|
|
|
|
});
|
2014-06-25 17:36:34 -03:00
|
|
|
});
|
2014-06-19 11:03:31 -07:00
|
|
|
|
2014-11-26 17:25:57 -03:00
|
|
|
describe('_getPubkeyToCopayerMap', function() {
|
2014-08-04 12:43:21 -03:00
|
|
|
var w = cachedCreateW();
|
|
|
|
|
|
|
|
|
|
it('should set keymap', function() {
|
2014-11-26 15:15:12 -03:00
|
|
|
var stub = sinon.stub(w.publicKeyRing, 'copayersForPubkeys').returns({
|
|
|
|
|
'123': 'juan'
|
2014-08-04 12:43:21 -03:00
|
|
|
});
|
|
|
|
|
var txp = {
|
2014-11-26 15:15:12 -03:00
|
|
|
getSignersPubKeys: sinon.stub().returns([
|
2014-08-04 12:43:21 -03:00
|
|
|
['123']
|
2014-11-26 15:15:12 -03:00
|
|
|
]),
|
2014-08-04 17:12:53 -03:00
|
|
|
inputChainPaths: ['/m/1'],
|
2014-08-04 12:43:21 -03:00
|
|
|
};
|
2014-11-26 17:25:57 -03:00
|
|
|
var map = w._getPubkeyToCopayerMap(txp);
|
2014-11-26 15:15:12 -03:00
|
|
|
console.log('[Wallet.js.1526:map:]', map); //TODO
|
2014-08-04 12:43:21 -03:00
|
|
|
Object.keys(map).length.should.equal(1);
|
|
|
|
|
map['123'].should.equal('juan');
|
|
|
|
|
stub.restore();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should throw if unmatched sigs', function() {
|
|
|
|
|
var stub = sinon.stub(w.publicKeyRing, 'copayersForPubkeys', function() {
|
2014-08-22 14:44:40 -04:00
|
|
|
return {};
|
2014-08-04 12:43:21 -03:00
|
|
|
});
|
|
|
|
|
var txp = {
|
2014-11-26 15:15:12 -03:00
|
|
|
getSignersPubKeys: sinon.stub().returns([
|
|
|
|
|
['123']
|
|
|
|
|
]),
|
2014-08-04 17:12:53 -03:00
|
|
|
inputChainPaths: ['/m/1'],
|
2014-08-04 12:43:21 -03:00
|
|
|
};
|
|
|
|
|
(function() {
|
2014-11-26 17:25:57 -03:00
|
|
|
w._getPubkeyToCopayerMap(txp);
|
2014-08-21 21:02:55 -04:00
|
|
|
}).should.throw('does not match known copayers');
|
|
|
|
|
stub.restore();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should throw if unmatched sigs (case 2)', function() {
|
|
|
|
|
var stub = sinon.stub(w.publicKeyRing, 'copayersForPubkeys', function() {
|
2014-08-22 14:44:40 -04:00
|
|
|
return {};
|
2014-08-21 21:02:55 -04:00
|
|
|
});
|
|
|
|
|
var txp = {
|
2014-11-26 15:15:12 -03:00
|
|
|
getSignersPubKeys: sinon.stub().returns([
|
2014-08-22 14:44:40 -04:00
|
|
|
['234', '321'],
|
|
|
|
|
['234', '322']
|
2014-11-26 15:15:12 -03:00
|
|
|
]),
|
2014-08-21 21:02:55 -04:00
|
|
|
inputChainPaths: ['/m/1'],
|
|
|
|
|
};
|
|
|
|
|
(function() {
|
2014-11-26 17:25:57 -03:00
|
|
|
w._getPubkeyToCopayerMap(txp);
|
2014-08-21 21:02:55 -04:00
|
|
|
}).should.throw('does not match known copayers');
|
2014-08-04 12:43:21 -03:00
|
|
|
stub.restore();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should set keymap with multiple signatures', function() {
|
|
|
|
|
var stub = sinon.stub(w.publicKeyRing, 'copayersForPubkeys', function() {
|
|
|
|
|
return {
|
|
|
|
|
'123': 'juan',
|
|
|
|
|
'234': 'pepe',
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
var txp = {
|
2014-11-26 15:15:12 -03:00
|
|
|
getSignersPubKeys: sinon.stub().returns([
|
|
|
|
|
['234', '321'],
|
|
|
|
|
]),
|
2014-08-04 17:12:53 -03:00
|
|
|
inputChainPaths: ['/m/1'],
|
2014-08-04 12:43:21 -03:00
|
|
|
};
|
2014-11-26 17:25:57 -03:00
|
|
|
var map = w._getPubkeyToCopayerMap(txp);
|
2014-08-04 12:43:21 -03:00
|
|
|
Object.keys(map).length.should.equal(2);
|
|
|
|
|
map['123'].should.equal('juan');
|
|
|
|
|
map['234'].should.equal('pepe');
|
|
|
|
|
stub.restore();
|
|
|
|
|
});
|
|
|
|
|
|
2014-08-21 21:02:55 -04:00
|
|
|
it('should throw if one inputs has missing sigs', function() {
|
2014-08-22 14:44:40 -04:00
|
|
|
var call = 0;
|
2014-08-04 12:43:21 -03:00
|
|
|
var stub = sinon.stub(w.publicKeyRing, 'copayersForPubkeys', function() {
|
2014-08-21 21:02:55 -04:00
|
|
|
return call++ ? {
|
|
|
|
|
'555': 'pepe',
|
2014-08-22 14:44:40 -04:00
|
|
|
} : {
|
2014-08-04 12:43:21 -03:00
|
|
|
'123': 'juan',
|
|
|
|
|
'234': 'pepe',
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
var txp = {
|
2014-11-26 15:15:12 -03:00
|
|
|
getSignersPubKeys: sinon.stub().returns([
|
2014-08-04 12:43:21 -03:00
|
|
|
['234', '123'],
|
2014-08-21 21:02:55 -04:00
|
|
|
['555']
|
2014-11-26 15:15:12 -03:00
|
|
|
]),
|
2014-11-26 17:25:57 -03:00
|
|
|
|
|
|
|
|
_inputSigners: [],
|
2014-08-04 17:12:53 -03:00
|
|
|
inputChainPaths: ['/m/1'],
|
2014-08-04 12:43:21 -03:00
|
|
|
};
|
|
|
|
|
(function() {
|
2014-11-26 17:25:57 -03:00
|
|
|
w._getPubkeyToCopayerMap(txp);
|
2014-08-04 12:43:21 -03:00
|
|
|
}).should.throw('different sig');
|
|
|
|
|
stub.restore();
|
|
|
|
|
});
|
2014-08-21 21:02:55 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
it('should throw if one inputs has different sigs', function() {
|
2014-08-22 14:44:40 -04:00
|
|
|
var call = 0;
|
2014-08-21 21:02:55 -04:00
|
|
|
var stub = sinon.stub(w.publicKeyRing, 'copayersForPubkeys', function() {
|
|
|
|
|
return call++ ? {
|
|
|
|
|
'555': 'pepe',
|
|
|
|
|
'666': 'pedro',
|
2014-08-22 14:44:40 -04:00
|
|
|
} : {
|
2014-08-21 21:02:55 -04:00
|
|
|
'123': 'juan',
|
|
|
|
|
'234': 'pepe',
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
var txp = {
|
2014-11-26 15:15:12 -03:00
|
|
|
getSignersPubKeys: sinon.stub().returns([
|
2014-08-21 21:02:55 -04:00
|
|
|
['234', '123'],
|
2014-11-26 15:15:12 -03:00
|
|
|
['555', '666'],
|
|
|
|
|
]),
|
2014-08-21 21:02:55 -04:00
|
|
|
inputChainPaths: ['/m/1'],
|
|
|
|
|
};
|
|
|
|
|
(function() {
|
2014-11-26 17:25:57 -03:00
|
|
|
w._getPubkeyToCopayerMap(txp);
|
2014-08-21 21:02:55 -04:00
|
|
|
}).should.throw('different sig');
|
|
|
|
|
stub.restore();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
it('should not throw if 2 inputs has different pubs, same copayers', function() {
|
2014-08-22 14:44:40 -04:00
|
|
|
var call = 0;
|
2014-08-21 21:02:55 -04:00
|
|
|
var stub = sinon.stub(w.publicKeyRing, 'copayersForPubkeys', function() {
|
|
|
|
|
return call++ ? {
|
|
|
|
|
'555': 'pepe',
|
|
|
|
|
'666': 'pedro',
|
2014-08-22 14:44:40 -04:00
|
|
|
} : {
|
2014-08-21 21:02:55 -04:00
|
|
|
'123': 'pedro',
|
|
|
|
|
'234': 'pepe',
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
var txp = {
|
2014-11-26 15:15:12 -03:00
|
|
|
getSignersPubKeys: sinon.stub().returns([
|
2014-08-21 21:02:55 -04:00
|
|
|
['234', '123'],
|
|
|
|
|
['555', '666']
|
2014-11-26 15:15:12 -03:00
|
|
|
]),
|
2014-08-21 21:02:55 -04:00
|
|
|
inputChainPaths: ['/m/1'],
|
|
|
|
|
};
|
2014-11-26 17:25:57 -03:00
|
|
|
var gk = w._getPubkeyToCopayerMap(txp);
|
2014-08-22 14:44:40 -04:00
|
|
|
gk.should.deep.equal({
|
|
|
|
|
'123': 'pedro',
|
|
|
|
|
'234': 'pepe',
|
|
|
|
|
'555': 'pepe',
|
|
|
|
|
'666': 'pedro'
|
|
|
|
|
});
|
2014-08-21 21:02:55 -04:00
|
|
|
stub.restore();
|
|
|
|
|
});
|
2014-08-04 12:43:21 -03:00
|
|
|
});
|
|
|
|
|
|
2014-12-02 15:18:56 -03:00
|
|
|
|
|
|
|
|
describe('_onPublicKeyRing', function() {
|
|
|
|
|
var w, data, txp, pkr;
|
|
|
|
|
beforeEach(function() {
|
|
|
|
|
w = cachedCreateW();
|
|
|
|
|
pkr = '{"walletId":"0a903a2eb33793d1","networkName":"testnet","requiredCopayers":2,"totalCopayers":2,"indexes":[{"copayerIndex":2147483647,"changeIndex":0,"receiveIndex":1},{"copayerIndex":0,"changeIndex":39,"receiveIndex":0},{"copayerIndex":1,"changeIndex":102,"receiveIndex":39}],"copayersExtPubKeys":["tpubD9peJo88ArhgmJNqRkQmhHt4zAGTYVowsHrDj385xyXyMy4RhWZpV5Qx2mMDUVzpbAD5V9jci5D7cZaHhjLYP8gEkngmTKtSF4Y7V3qkAsy","tpubD8udwzKWwNUgoE2WG7LYsXKf5m1eRtJ1Etp43vnoxViFmrmZ1ND2CkdqGyQtuidcN1CiqdBUvbKegbdsMQaj5VLY2hbA4LEnLDrqkgSzikz"],"nicknameFor":{"03338b105850c7126f1f5b0439b357765b17ead8eed15bcdfdbd28d0e3915b696f":"5@queparece","0286b376d65cc4af0de5932fb8299cbef2ca9ed37ec9fdb0edfd4e9cb74eac45da":"4@queparece"}}';
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should fail wrong nr copayers PublicKeyRing', function() {
|
|
|
|
|
var spy = sinon.spy(console, 'warn');
|
|
|
|
|
w._onPublicKeyRing('sender', {
|
|
|
|
|
publicKeyRing: JSON.parse(pkr),
|
|
|
|
|
});
|
|
|
|
|
spy.getCall(0).args[1].toString().should.contain('mismatch');
|
|
|
|
|
spy.restore();
|
|
|
|
|
});
|
|
|
|
|
it('should receive and send PKR', function() {
|
|
|
|
|
var obj = JSON.parse(pkr);
|
|
|
|
|
|
|
|
|
|
sinon.stub(w.network, 'send').returns();
|
|
|
|
|
|
|
|
|
|
obj.requiredCopayers = 3;
|
|
|
|
|
obj.totalCopayers = 5;
|
|
|
|
|
w._onPublicKeyRing('sender', {
|
|
|
|
|
publicKeyRing: obj,
|
|
|
|
|
});
|
|
|
|
|
w.network.send.calledOnce.should.equal(true);
|
|
|
|
|
should.not.exist(w.network.send.getCall(0).args[0])
|
|
|
|
|
var o = w.network.send.getCall(0).args[1];
|
|
|
|
|
_.isObject(o).should.equal(true);
|
|
|
|
|
o.type.should.equal('publicKeyRing');
|
|
|
|
|
});
|
|
|
|
|
it('should lock incomming connections', function() {
|
|
|
|
|
var obj = JSON.parse(pkr);
|
|
|
|
|
sinon.stub(w.network, 'send').returns();
|
|
|
|
|
sinon.stub(w.network, 'lockIncommingConnections').returns();
|
|
|
|
|
|
|
|
|
|
obj.requiredCopayers = 3;
|
|
|
|
|
obj.totalCopayers = 5;
|
|
|
|
|
var s = sinon.stub(w.publicKeyRing, 'isComplete');
|
|
|
|
|
s.returns(true);
|
|
|
|
|
|
|
|
|
|
w._onPublicKeyRing('sender', {
|
|
|
|
|
publicKeyRing: obj,
|
|
|
|
|
});
|
|
|
|
|
w.network.send.calledOnce.should.equal(false); // wasComplete
|
|
|
|
|
w.network.lockIncommingConnections.calledOnce.should.equal(true);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2014-11-27 17:45:10 -03:00
|
|
|
describe('_onTxProposal', function() {
|
2014-11-25 09:45:44 -03:00
|
|
|
var w, data, txp;
|
2014-09-29 17:36:34 -03:00
|
|
|
beforeEach(function() {
|
|
|
|
|
w = cachedCreateW();
|
2014-11-25 09:45:44 -03:00
|
|
|
data = {
|
2014-09-29 17:36:34 -03:00
|
|
|
txProposal: {
|
|
|
|
|
dummy: 1,
|
2014-11-27 17:45:10 -03:00
|
|
|
builderObj: {
|
|
|
|
|
dummy: 1,
|
|
|
|
|
},
|
2014-09-29 17:36:34 -03:00
|
|
|
},
|
|
|
|
|
};
|
2014-11-26 15:15:12 -03:00
|
|
|
txp = {
|
2014-11-27 17:45:10 -03:00
|
|
|
getId: sinon.stub().returns('ntxid'),
|
2014-11-26 15:15:12 -03:00
|
|
|
getSeen: sinon.stub().returns(false),
|
|
|
|
|
setSeen: sinon.spy(),
|
|
|
|
|
setCopayers: sinon.spy(),
|
|
|
|
|
builder: {
|
|
|
|
|
build: sinon.stub().returns({
|
|
|
|
|
isComplete: sinon.stub().returns(false),
|
|
|
|
|
}),
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
2014-11-27 17:45:10 -03:00
|
|
|
sinon.stub(w, '_processIncomingNewTxProposal').yields(null);
|
|
|
|
|
sinon.stub(w.txProposals, 'get').returns(null);
|
2014-11-25 09:45:44 -03:00
|
|
|
sinon.stub(w.txProposals, 'deleteOne');
|
2014-11-27 17:45:10 -03:00
|
|
|
sinon.stub(w, '_txProposalFromUntrustedObj').returns(txp);
|
|
|
|
|
sinon.stub(w, '_getPubkeyToCopayerMap');
|
2014-11-25 09:45:44 -03:00
|
|
|
});
|
|
|
|
|
|
2014-11-27 17:45:10 -03:00
|
|
|
afterEach(function() {});
|
2014-08-03 23:57:23 -03:00
|
|
|
|
2014-11-27 17:45:10 -03:00
|
|
|
it('should handle corrupt message', function() {
|
|
|
|
|
w._txProposalFromUntrustedObj.throws('error');
|
2014-11-25 09:45:44 -03:00
|
|
|
w._onTxProposal('senderID', data);
|
2014-11-27 17:45:10 -03:00
|
|
|
w._processIncomingNewTxProposal.called.should.equal(false);
|
2014-11-25 09:45:44 -03:00
|
|
|
});
|
|
|
|
|
|
2014-11-27 17:45:10 -03:00
|
|
|
it('should ignore localTx', function() {
|
|
|
|
|
w.txProposals.get = sinon.stub().returns(txp);
|
|
|
|
|
w._txProposalFromUntrustedObj.throws('error');
|
|
|
|
|
w._onTxProposal('senderID', data);
|
|
|
|
|
w._processIncomingNewTxProposal.called.should.equal(false);
|
|
|
|
|
});
|
2014-09-29 17:36:34 -03:00
|
|
|
|
2014-11-27 17:45:10 -03:00
|
|
|
it('should accept a new valid TXP', function(done) {
|
|
|
|
|
w.txProposals.get = sinon.stub().returns(null);
|
2014-11-25 09:45:44 -03:00
|
|
|
w.on('txProposalEvent', function(e) {
|
|
|
|
|
e.type.should.equal('new');
|
2014-11-27 17:45:10 -03:00
|
|
|
w._processIncomingNewTxProposal.called.should.equal(true);
|
|
|
|
|
w._getPubkeyToCopayerMap.called.should.equal(true);
|
2014-11-25 09:45:44 -03:00
|
|
|
done();
|
2014-11-27 17:45:10 -03:00
|
|
|
})
|
2014-09-29 17:36:34 -03:00
|
|
|
w._onTxProposal('senderID', data);
|
|
|
|
|
});
|
|
|
|
|
|
2014-11-25 09:45:44 -03:00
|
|
|
|
2014-11-27 17:45:10 -03:00
|
|
|
it('should ignore is a TXP arrived 2 times', function(done) {
|
|
|
|
|
w.txProposals.get = sinon.stub().returns(null);
|
|
|
|
|
var secondCall = false;
|
2014-09-29 17:36:34 -03:00
|
|
|
w.on('txProposalEvent', function(e) {
|
|
|
|
|
e.type.should.equal('new');
|
2014-11-27 17:45:10 -03:00
|
|
|
w._processIncomingNewTxProposal.calledOnce.should.equal(true);
|
|
|
|
|
w._getPubkeyToCopayerMap.called.should.equal(true);
|
|
|
|
|
w._onTxProposal('senderID', data);
|
|
|
|
|
w._processIncomingNewTxProposal.calledOnce.should.equal(true);
|
2014-09-29 17:36:34 -03:00
|
|
|
done();
|
2014-11-27 17:45:10 -03:00
|
|
|
})
|
2014-09-29 17:36:34 -03:00
|
|
|
w._onTxProposal('senderID', data);
|
|
|
|
|
});
|
|
|
|
|
|
2014-11-27 17:45:10 -03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
it('should handle a real txp correctly', function(done) {
|
|
|
|
|
w._txProposalFromUntrustedObj.restore();
|
|
|
|
|
w._getPubkeyToCopayerMap.restore();
|
2014-09-29 17:36:34 -03:00
|
|
|
var txp = {
|
2014-11-27 17:45:10 -03:00
|
|
|
'txProposal': {
|
|
|
|
|
inputChainPaths: ['m/1'],
|
|
|
|
|
builderObj: {
|
|
|
|
|
version: 1,
|
|
|
|
|
outs: [{
|
|
|
|
|
address: '15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
|
|
|
|
amountSatStr: '123456789'
|
|
|
|
|
}],
|
|
|
|
|
utxos: [{
|
|
|
|
|
address: '2N6fdPg2QL7V36XKe7a8wkkA5HCy7fNYmZF',
|
|
|
|
|
scriptPubKey: 'a91493372782bab70f4eefdefefea8ece0df44f9596887',
|
|
|
|
|
txid: '2ac165fa7a3a2b535d106a0041c7568d03b531e58aeccdd3199d7289ab12cfc1',
|
|
|
|
|
vout: 1,
|
|
|
|
|
amount: 10,
|
|
|
|
|
confirmations: 7
|
|
|
|
|
}],
|
|
|
|
|
opts: {
|
|
|
|
|
remainderOut: {
|
|
|
|
|
address: '2N7BLvdrxJ4YzDtb3hfgt6CMY5rrw5kNT1H'
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
scriptSig: ['00493046022100b8249a4fc326c4c33882e9d5468a1c6faa01e8c6cef0a24970122e804abdd860022100dbf6ee3b07d3aad8f73997e62ad20654a08aa63a7609792d02f3d5d088e69ad9014cad5321027445ab3a935dce7aee1dadb0d103ed6147a0f83deb80474a04538b2c5bc4d5092102ab32ba51402a139873aeb919c738f5a945f3956f8f8c6ba296677bd29e85d7e821036f119b72e09f76c11ebe2cf754d64eac2cb42c9e623455d54aaa89d70c11f9c82103bcbd3f8ab2c849ea9eae434733cee8b75120d26233def56011b3682ca12081d72103f37f81dc534163b9f73ecf36b91e6c3fb8ae370c24618f91bb1d972e86ceeee255ae'],
|
|
|
|
|
hashToScriptMap: {
|
|
|
|
|
'2N6fdPg2QL7V36XKe7a8wkkA5HCy7fNYmZF': '5321027445ab3a935dce7aee1dadb0d103ed6147a0f83deb80474a04538b2c5bc4d5092102ab32ba51402a139873aeb919c738f5a945f3956f8f8c6ba296677bd29e85d7e821036f119b72e09f76c11ebe2cf754d64eac2cb42c9e623455d54aaa89d70c11f9c82103bcbd3f8ab2c849ea9eae434733cee8b75120d26233def56011b3682ca12081d72103f37f81dc534163b9f73ecf36b91e6c3fb8ae370c24618f91bb1d972e86ceeee255ae'
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-09-29 17:36:34 -03:00
|
|
|
};
|
|
|
|
|
|
2014-11-27 17:45:10 -03:00
|
|
|
var stub = sinon.stub(w.publicKeyRing, 'copayersForPubkeys').returns({
|
|
|
|
|
'027445ab3a935dce7aee1dadb0d103ed6147a0f83deb80474a04538b2c5bc4d509': 'pepe'
|
2014-08-01 10:51:46 -03:00
|
|
|
});
|
2014-09-29 17:36:34 -03:00
|
|
|
w.on('txProposalEvent', function(e) {
|
2014-11-27 17:45:10 -03:00
|
|
|
Object.keys(w.txProposals.txps).length.should.equal(1);
|
2014-09-29 17:36:34 -03:00
|
|
|
done();
|
|
|
|
|
});
|
2014-11-27 17:45:10 -03:00
|
|
|
w._onTxProposal('senderID', txp, true);
|
2014-07-25 13:37:12 -03:00
|
|
|
});
|
2014-11-27 17:45:10 -03:00
|
|
|
});
|
2014-09-29 17:36:34 -03:00
|
|
|
|
|
|
|
|
|
2014-11-27 17:45:10 -03:00
|
|
|
describe('_onSignature', function() {
|
|
|
|
|
var w, data, txp;
|
|
|
|
|
beforeEach(function() {
|
|
|
|
|
w = cachedCreateW2();
|
2014-08-03 23:57:23 -03:00
|
|
|
});
|
|
|
|
|
|
2014-11-27 17:45:10 -03:00
|
|
|
afterEach(function() {});
|
2014-10-06 18:51:45 -03:00
|
|
|
|
2014-11-27 17:45:10 -03:00
|
|
|
it('should handle corrupt message', function() {
|
|
|
|
|
w._onSignature('senderID', 'sigs');
|
2014-10-06 18:51:45 -03:00
|
|
|
});
|
|
|
|
|
|
2014-11-27 17:45:10 -03:00
|
|
|
it('should sign a txp', function(done) {
|
|
|
|
|
var utxo = createUTXO(w);
|
|
|
|
|
var txp = w._createTxProposal(PP.outs[0].address, PP.outs[0].amountSatStr, 'hola', utxo);
|
|
|
|
|
var ntxid = w.txProposals.add(txp);
|
|
|
|
|
sinon.stub(w.blockchain, 'broadcast').yields(null, 1234);
|
|
|
|
|
data = {
|
|
|
|
|
ntxid: ntxid,
|
|
|
|
|
signatures: [1],
|
|
|
|
|
}
|
|
|
|
|
sinon.stub(w.txProposals, 'get').returns(txp);
|
|
|
|
|
sinon.stub(txp, '_addSignatureAndVerify').returns();
|
2014-09-29 17:36:34 -03:00
|
|
|
|
2014-11-27 17:45:10 -03:00
|
|
|
w.on('txProposalEvent', function(e) {
|
|
|
|
|
e.type.should.equal('signed');
|
|
|
|
|
done();
|
|
|
|
|
})
|
|
|
|
|
w._onSignature('senderID', data);
|
2014-09-29 17:36:34 -03:00
|
|
|
});
|
2014-11-27 17:45:10 -03:00
|
|
|
|
2014-07-24 10:42:47 -03:00
|
|
|
});
|
2014-08-04 12:43:21 -03:00
|
|
|
|
|
|
|
|
|
2014-08-19 12:51:55 -04:00
|
|
|
describe('_onReject', function() {
|
2014-11-25 17:44:51 -03:00
|
|
|
it('should do nothing on unknown tx', function() {
|
2014-08-04 12:43:21 -03:00
|
|
|
var w = cachedCreateW();
|
2014-11-25 17:44:51 -03:00
|
|
|
var spy1 = sinon.spy(w, 'emitAndKeepAlive');
|
|
|
|
|
w._onReject(1, {
|
|
|
|
|
ntxid: 1
|
|
|
|
|
}, 1);
|
|
|
|
|
spy1.called.should.equal(false);
|
2014-08-04 12:43:21 -03:00
|
|
|
});
|
|
|
|
|
it('should fail to reject a signed tx', function() {
|
|
|
|
|
var w = cachedCreateW();
|
|
|
|
|
w.txProposals.txps['qwerty'] = {
|
|
|
|
|
signedBy: {
|
|
|
|
|
john: 1
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
(function() {
|
2014-08-19 12:51:55 -04:00
|
|
|
w._onReject('john', {
|
2014-08-04 12:43:21 -03:00
|
|
|
ntxid: 'qwerty'
|
|
|
|
|
}, 1);
|
|
|
|
|
}).should.throw('already signed');
|
|
|
|
|
});
|
|
|
|
|
it('should reject a tx', function() {
|
|
|
|
|
var w = cachedCreateW();
|
2014-08-04 17:12:53 -03:00
|
|
|
|
2014-08-04 12:43:21 -03:00
|
|
|
function txp() {
|
2014-08-04 17:12:53 -03:00
|
|
|
this.ok = 0;
|
2014-08-04 12:43:21 -03:00
|
|
|
this.signedBy = {};
|
|
|
|
|
};
|
2014-08-04 17:12:53 -03:00
|
|
|
txp.prototype.setRejected = function() {
|
|
|
|
|
this.ok = 1;
|
2014-08-04 12:43:21 -03:00
|
|
|
};
|
2014-08-04 17:12:53 -03:00
|
|
|
txp.prototype.toObj = function() {};
|
2014-08-04 12:43:21 -03:00
|
|
|
|
2014-10-27 13:13:08 -03:00
|
|
|
var spy1 = sinon.spy(w, 'emitAndKeepAlive');
|
2014-08-04 17:12:53 -03:00
|
|
|
var spy2 = sinon.spy(w, 'emit');
|
2014-08-04 12:43:21 -03:00
|
|
|
w.txProposals.txps['qwerty'] = new txp();
|
2014-08-04 17:12:53 -03:00
|
|
|
w.txProposals.txps['qwerty'].ok.should.equal(0);
|
2014-10-27 13:13:08 -03:00
|
|
|
spy2.callCount.should.equal(0);
|
2014-08-19 12:51:55 -04:00
|
|
|
w._onReject('john', {
|
2014-08-04 12:43:21 -03:00
|
|
|
ntxid: 'qwerty'
|
|
|
|
|
}, 1);
|
2014-08-04 17:12:53 -03:00
|
|
|
w.txProposals.txps['qwerty'].ok.should.equal(1);
|
2014-08-04 12:43:21 -03:00
|
|
|
spy1.calledOnce.should.equal(true);
|
2014-10-27 13:13:08 -03:00
|
|
|
spy2.callCount.should.equal(1);
|
|
|
|
|
spy2.firstCall.args.should.deep.equal(['txProposalEvent', {
|
2014-08-04 17:12:53 -03:00
|
|
|
type: 'rejected',
|
2014-08-04 12:43:21 -03:00
|
|
|
cId: 'john',
|
|
|
|
|
txId: 'qwerty',
|
|
|
|
|
}]);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
2014-08-19 12:51:55 -04:00
|
|
|
describe('_onSeen', function() {
|
2014-11-25 17:44:51 -03:00
|
|
|
it('should do nothing on unknown tx', function() {
|
2014-08-04 12:43:21 -03:00
|
|
|
var w = cachedCreateW();
|
2014-11-25 17:44:51 -03:00
|
|
|
var spy1 = sinon.spy(w, 'emitAndKeepAlive');
|
|
|
|
|
w._onReject(1, {
|
|
|
|
|
ntxid: 1
|
|
|
|
|
}, 1);
|
|
|
|
|
spy1.called.should.equal(false);
|
2014-08-04 12:43:21 -03:00
|
|
|
});
|
|
|
|
|
it('should set seen a tx', function() {
|
|
|
|
|
var w = cachedCreateW();
|
2014-08-04 17:12:53 -03:00
|
|
|
|
2014-08-04 12:43:21 -03:00
|
|
|
function txp() {
|
2014-08-04 17:12:53 -03:00
|
|
|
this.ok = 0;
|
2014-08-04 12:43:21 -03:00
|
|
|
this.signedBy = {};
|
|
|
|
|
};
|
2014-08-04 17:12:53 -03:00
|
|
|
txp.prototype.setSeen = function() {
|
|
|
|
|
this.ok = 1;
|
2014-08-04 12:43:21 -03:00
|
|
|
};
|
2014-08-04 17:12:53 -03:00
|
|
|
txp.prototype.toObj = function() {};
|
2014-08-04 12:43:21 -03:00
|
|
|
|
2014-10-27 13:13:08 -03:00
|
|
|
var spy2 = sinon.spy(w, 'emitAndKeepAlive');
|
2014-08-04 12:43:21 -03:00
|
|
|
w.txProposals.txps['qwerty'] = new txp();
|
2014-08-04 17:12:53 -03:00
|
|
|
w.txProposals.txps['qwerty'].ok.should.equal(0);
|
2014-08-19 12:51:55 -04:00
|
|
|
w._onSeen('john', {
|
2014-08-04 12:43:21 -03:00
|
|
|
ntxid: 'qwerty'
|
|
|
|
|
}, 1);
|
2014-08-04 17:12:53 -03:00
|
|
|
w.txProposals.txps['qwerty'].ok.should.equal(1);
|
2014-10-27 13:13:08 -03:00
|
|
|
spy2.callCount.should.equal(1);
|
|
|
|
|
spy2.firstCall.args.should.deep.equal(['txProposalEvent', {
|
2014-08-04 17:12:53 -03:00
|
|
|
type: 'seen',
|
2014-08-04 12:43:21 -03:00
|
|
|
cId: 'john',
|
|
|
|
|
txId: 'qwerty',
|
|
|
|
|
}]);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('getNetwork', function() {
|
|
|
|
|
var w = cachedCreateW();
|
|
|
|
|
var n = w.getNetwork();
|
|
|
|
|
n.maxPeers.should.equal(5);
|
|
|
|
|
should.exist(n.networkNonce);
|
|
|
|
|
});
|
|
|
|
|
|
2014-09-29 11:35:04 -03:00
|
|
|
|
2014-11-26 17:25:57 -03:00
|
|
|
describe('sendMesages', function() {
|
|
|
|
|
var w, txp;
|
|
|
|
|
beforeEach(function() {
|
|
|
|
|
w = createW2(null, 1);
|
|
|
|
|
var utxo = createUTXO(w);
|
|
|
|
|
txp = w._createTxProposal(
|
|
|
|
|
'2MtP8WyiwG7ZdVWM96CVsk2M1N8zyfiVQsY',
|
|
|
|
|
'123456789',
|
|
|
|
|
null,
|
|
|
|
|
utxo
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should be able to sendReject', function() {
|
|
|
|
|
w.sendReject(txp.getId());
|
|
|
|
|
w.network.send.calledOnce.should.equal(true);
|
|
|
|
|
var payload = w.network.send.getCall(0).args[1];
|
|
|
|
|
payload.type.should.equal('reject');
|
|
|
|
|
payload.walletId.should.equal(w.id);
|
|
|
|
|
payload.ntxid.should.equal(txp.getId());
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
it('should be able to sendSend', function() {
|
|
|
|
|
w.sendSeen(txp.getId());
|
|
|
|
|
w.network.send.calledOnce.should.equal(true);
|
|
|
|
|
var payload = w.network.send.getCall(0).args[1];
|
|
|
|
|
payload.type.should.equal('seen');
|
|
|
|
|
payload.walletId.should.equal(w.id);
|
|
|
|
|
payload.ntxid.should.equal(txp.getId());
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should be able to sendTxProposal', function() {
|
|
|
|
|
w.txProposals.add(txp);
|
|
|
|
|
w.sendTxProposal(txp.getId());
|
|
|
|
|
w.network.send.calledOnce.should.equal(true);
|
|
|
|
|
var payload = w.network.send.getCall(0).args[1];
|
|
|
|
|
payload.type.should.equal('txProposal');
|
|
|
|
|
payload.walletId.should.equal(w.id);
|
|
|
|
|
payload.txProposal.should.deep.equal(txp.toObjTrim());
|
|
|
|
|
});
|
|
|
|
|
it('should be able to sendAllTxProposals', function() {
|
|
|
|
|
w.txProposals.add(txp);
|
|
|
|
|
w.sendAllTxProposals();
|
|
|
|
|
w.network.send.calledOnce.should.equal(true);
|
|
|
|
|
var payload = w.network.send.getCall(0).args[1];
|
|
|
|
|
payload.type.should.equal('txProposal');
|
|
|
|
|
payload.walletId.should.equal(w.id);
|
|
|
|
|
payload.txProposal.should.deep.equal(txp.toObjTrim());
|
|
|
|
|
});
|
|
|
|
|
it('should be able to sendSignature', function() {
|
|
|
|
|
w.txProposals.add(txp);
|
|
|
|
|
w.sendSignature(txp.getId());
|
|
|
|
|
w.network.send.calledOnce.should.equal(true);
|
|
|
|
|
var payload = w.network.send.getCall(0).args[1];
|
|
|
|
|
payload.type.should.equal('signature');
|
|
|
|
|
payload.walletId.should.equal(w.id);
|
|
|
|
|
payload.signatures.length.should.equal(1);
|
2014-11-27 17:45:10 -03:00
|
|
|
var sig = new Buffer(payload.signatures[0], 'hex');
|
2014-11-26 17:25:57 -03:00
|
|
|
sig.length.should.be.above(70);
|
|
|
|
|
sig.length.should.be.below(74);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2014-09-29 11:35:04 -03:00
|
|
|
describe('#obtainNetworkName', function() {
|
|
|
|
|
it('should return the networkname', function() {
|
|
|
|
|
Wallet.obtainNetworkName({
|
|
|
|
|
networkName: 'testnet',
|
|
|
|
|
}).should.equal('testnet');
|
|
|
|
|
Wallet.obtainNetworkName({
|
|
|
|
|
opts: {
|
|
|
|
|
networkName: 'testnet'
|
|
|
|
|
}
|
|
|
|
|
}).should.equal('testnet');
|
|
|
|
|
Wallet.obtainNetworkName({
|
|
|
|
|
publicKeyRing: {
|
|
|
|
|
networkName: 'testnet'
|
|
|
|
|
}
|
|
|
|
|
}).should.equal('testnet');
|
2014-09-29 19:58:00 -03:00
|
|
|
|
2014-09-29 11:35:04 -03:00
|
|
|
Wallet.obtainNetworkName({
|
|
|
|
|
privateKey: {
|
|
|
|
|
networkName: 'testnet'
|
|
|
|
|
}
|
|
|
|
|
}).should.equal('testnet');
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-11-28 18:43:22 -03:00
|
|
|
it('should emit notification when tx received', function() {
|
2014-09-17 17:34:00 -03:00
|
|
|
var w = cachedCreateW2();
|
2014-11-28 18:43:22 -03:00
|
|
|
|
|
|
|
|
var addr1 = w.generateAddress(false);
|
2014-12-02 15:18:56 -03:00
|
|
|
sinon.stub(w, 'subscribeToAddresses');
|
2014-11-28 18:43:22 -03:00
|
|
|
|
2014-09-17 17:34:00 -03:00
|
|
|
w.blockchain.removeAllListeners = sinon.stub();
|
2014-11-28 18:43:22 -03:00
|
|
|
w.blockchain.on = sinon.stub();
|
|
|
|
|
|
|
|
|
|
w.blockchain.on.withArgs('tx').yields({
|
|
|
|
|
address: addr1,
|
|
|
|
|
});
|
|
|
|
|
|
2014-09-17 17:34:00 -03:00
|
|
|
var spy = sinon.spy(w, 'emit');
|
2014-11-30 18:55:15 -03:00
|
|
|
w._setupBlockchainHandlers();
|
2014-11-28 18:43:22 -03:00
|
|
|
spy.calledWith('tx', addr1, false).should.equal(true);
|
|
|
|
|
});
|
2014-09-17 17:34:00 -03:00
|
|
|
|
2014-11-28 18:43:22 -03:00
|
|
|
it('should emit notification when tx received (change addr)', function() {
|
|
|
|
|
var w = cachedCreateW2();
|
2014-09-17 17:34:00 -03:00
|
|
|
|
2014-11-28 18:43:22 -03:00
|
|
|
var addr1 = w.generateAddress(true);
|
2014-12-02 15:18:56 -03:00
|
|
|
sinon.stub(w, 'subscribeToAddresses');
|
2014-11-28 18:43:22 -03:00
|
|
|
|
|
|
|
|
w.blockchain.removeAllListeners = sinon.stub();
|
|
|
|
|
w.blockchain.on = sinon.stub();
|
|
|
|
|
|
|
|
|
|
w.blockchain.on.withArgs('tx').yields({
|
|
|
|
|
address: addr1,
|
2014-09-17 17:34:00 -03:00
|
|
|
});
|
2014-11-28 18:43:22 -03:00
|
|
|
|
|
|
|
|
var spy = sinon.spy(w, 'emit');
|
2014-11-30 18:55:15 -03:00
|
|
|
w._setupBlockchainHandlers();
|
2014-11-28 18:43:22 -03:00
|
|
|
spy.calledWith('tx', addr1, true).should.equal(true);
|
2014-09-17 17:34:00 -03:00
|
|
|
});
|
|
|
|
|
|
2014-09-29 10:18:47 -03:00
|
|
|
describe('#fromObj / #toObj', function() {
|
|
|
|
|
var network = new Network(walletConfig.network);
|
|
|
|
|
var blockchain = new Blockchain(walletConfig.blockchain);
|
|
|
|
|
|
|
|
|
|
it('Import backup using old copayerIndex', function() {
|
2014-10-07 18:33:55 -03:00
|
|
|
|
|
|
|
|
var w = Wallet.fromObj(JSON.parse(o), {
|
|
|
|
|
blockchainOpts: {},
|
|
|
|
|
networkOpts: {},
|
|
|
|
|
});
|
2014-09-29 10:18:47 -03:00
|
|
|
|
|
|
|
|
should.exist(w);
|
|
|
|
|
w.id.should.equal("dbfe10c3fae71cea");
|
|
|
|
|
should.exist(w.publicKeyRing.getCopayerId);
|
|
|
|
|
should.exist(w.txProposals.toObj());
|
|
|
|
|
should.exist(w.privateKey.toObj());
|
|
|
|
|
assertObjectEqual(w.toObj(), JSON.parse(o));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('#fromObj, skipping fields', function() {
|
2014-10-07 18:33:55 -03:00
|
|
|
var w = Wallet.fromObj(JSON.parse(o), {
|
|
|
|
|
networkOpts: {},
|
|
|
|
|
blockchainOpts: {},
|
|
|
|
|
skipFields: ['publicKeyRing'],
|
|
|
|
|
});
|
2014-09-29 10:18:47 -03:00
|
|
|
|
|
|
|
|
should.exist(w);
|
|
|
|
|
w.id.should.equal("dbfe10c3fae71cea");
|
|
|
|
|
should.exist(w.publicKeyRing.getCopayerId);
|
|
|
|
|
should.exist(w.txProposals.toObj());
|
|
|
|
|
should.exist(w.privateKey.toObj());
|
|
|
|
|
(function() {
|
|
|
|
|
assertObjectEqual(w.toObj(), JSON.parse(o))
|
|
|
|
|
}).should.throw();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('support old index schema: #fromObj #toObj round trip', function() {
|
2014-10-28 15:56:03 -03:00
|
|
|
var o = '{"opts":{"id":"dbfe10c3fae71cea","spendUnconfirmed":1,"requiredCopayers":3,"totalCopayers":5,"version":"0.0.5"},"networkNonce":"0000000000000001","networkNonces":[],"publicKeyRing":{"walletId":"dbfe10c3fae71cea","networkName":"testnet","requiredCopayers":3,"totalCopayers":5,"indexes":{"changeIndex":0,"receiveIndex":0},"copayersExtPubKeys":["tpubD6NzVbkrYhZ4YGK8ZhZ8WVeBXNAAoTYjjpw9twCPiNGrGQYFktP3iVQkKmZNiFnUcAFMJRxJVJF6Nq9MDv2kiRceExJaHFbxUCGUiRhmy97","tpubD6NzVbkrYhZ4YKGDJkzWdQsQV3AcFemaQKiwNhV4RL8FHnBFvinidGdQtP8RKj3h34E65RkdtxjrggZYqsEwJ8RhhN2zz9VrjLnrnwbXYNc","tpubD6NzVbkrYhZ4YkDiewjb32Pp3Sz9WK2jpp37KnL7RCrHAyPpnLfgdfRnTdpn6DTWmPS7niywfgWiT42aJb1J6CjWVNmkgsMCxuw7j9DaGKB","tpubD6NzVbkrYhZ4XEtUAz4UUTWbprewbLTaMhR8NUvSJUEAh4Sidxr6rRPFdqqVRR73btKf13wUjds2i8vVCNo8sbKrAnyoTr3o5Y6QSbboQjk","tpubD6NzVbkrYhZ4Yj9AAt6xUVuGPVd8jXCrEE6V2wp7U3PFh8jYYvVad31b4VUXEYXzSnkco4fktu8r4icBsB2t3pCR3WnhVLedY2hxGcPFLKD"],"nicknameFor":{}},"txProposals":{"txps":[],"walletId":"dbfe10c3fae71cea","networkName":"testnet"},"privateKey":{"extendedPrivateKeyString":"tprv8ZgxMBicQKsPeoHLg3tY75z4xLeEe8MqAXLNcRA6J6UTRvHV8VZTXznt9eoTmSk1fwSrwZtMhY3XkNsceJ14h6sCXHSWinRqMSSbY8tfhHi","networkName":"testnet"},"addressBook":{}}';
|
|
|
|
|
var o2 = '{"opts":{"id":"dbfe10c3fae71cea","spendUnconfirmed":1,"requiredCopayers":3,"totalCopayers":5,"version":"0.0.5","networkName":"testnet"},"networkNonce":"0000000000000001","networkNonces":[],"publicKeyRing":{"walletId":"dbfe10c3fae71cea","networkName":"testnet","requiredCopayers":3,"totalCopayers":5,"indexes":[{"copayerIndex":2147483647,"changeIndex":0,"receiveIndex":0},{"copayerIndex":0,"changeIndex":0,"receiveIndex":0},{"copayerIndex":1,"changeIndex":0,"receiveIndex":0},{"copayerIndex":2,"changeIndex":0,"receiveIndex":0},{"copayerIndex":3,"changeIndex":0,"receiveIndex":0},{"copayerIndex":4,"changeIndex":0,"receiveIndex":0}],"copayersExtPubKeys":["tpubD6NzVbkrYhZ4YGK8ZhZ8WVeBXNAAoTYjjpw9twCPiNGrGQYFktP3iVQkKmZNiFnUcAFMJRxJVJF6Nq9MDv2kiRceExJaHFbxUCGUiRhmy97","tpubD6NzVbkrYhZ4YKGDJkzWdQsQV3AcFemaQKiwNhV4RL8FHnBFvinidGdQtP8RKj3h34E65RkdtxjrggZYqsEwJ8RhhN2zz9VrjLnrnwbXYNc","tpubD6NzVbkrYhZ4YkDiewjb32Pp3Sz9WK2jpp37KnL7RCrHAyPpnLfgdfRnTdpn6DTWmPS7niywfgWiT42aJb1J6CjWVNmkgsMCxuw7j9DaGKB","tpubD6NzVbkrYhZ4XEtUAz4UUTWbprewbLTaMhR8NUvSJUEAh4Sidxr6rRPFdqqVRR73btKf13wUjds2i8vVCNo8sbKrAnyoTr3o5Y6QSbboQjk","tpubD6NzVbkrYhZ4Yj9AAt6xUVuGPVd8jXCrEE6V2wp7U3PFh8jYYvVad31b4VUXEYXzSnkco4fktu8r4icBsB2t3pCR3WnhVLedY2hxGcPFLKD"],"nicknameFor":{}},"txProposals":{"txps":[],"walletId":"dbfe10c3fae71cea","networkName":"testnet"},"privateKey":{"extendedPrivateKeyString":"tprv8ZgxMBicQKsPeoHLg3tY75z4xLeEe8MqAXLNcRA6J6UTRvHV8VZTXznt9eoTmSk1fwSrwZtMhY3XkNsceJ14h6sCXHSWinRqMSSbY8tfhHi","networkName":"testnet"},"addressBook":{}}';
|
2014-09-29 10:18:47 -03:00
|
|
|
|
2014-10-07 18:33:55 -03:00
|
|
|
var w = Wallet.fromObj(JSON.parse(o), {
|
|
|
|
|
networkOpts: {},
|
|
|
|
|
blockchainOpts: {},
|
|
|
|
|
});
|
2014-09-29 10:18:47 -03:00
|
|
|
|
|
|
|
|
should.exist(w);
|
|
|
|
|
w.id.should.equal("dbfe10c3fae71cea");
|
|
|
|
|
should.exist(w.publicKeyRing.getCopayerId);
|
|
|
|
|
should.exist(w.txProposals.toObj);
|
|
|
|
|
should.exist(w.privateKey.toObj);
|
|
|
|
|
|
2014-11-28 18:43:22 -03:00
|
|
|
var obj = w.toObj();
|
|
|
|
|
|
|
|
|
|
// remove data from new versions
|
|
|
|
|
delete obj.publicKeyRing['cache'];
|
|
|
|
|
|
|
|
|
|
assertObjectEqual(obj, JSON.parse(o2));
|
2014-09-29 10:18:47 -03:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2014-10-22 16:57:29 -03:00
|
|
|
describe('#getTransactionHistory', function() {
|
2014-11-28 18:43:22 -03:00
|
|
|
var w;
|
|
|
|
|
beforeEach(function() {
|
|
|
|
|
w = cachedCreateW2();
|
|
|
|
|
});
|
|
|
|
|
afterEach(function() {
|
|
|
|
|
if (w.publicKeyRing.addressIsOwn.restore)
|
|
|
|
|
w.publicKeyRing.addressIsOwn.restore();
|
|
|
|
|
if (w.publicKeyRing.addressIsChange.restore)
|
|
|
|
|
w.publicKeyRing.addressIsChange.restore();
|
|
|
|
|
});
|
|
|
|
|
|
2014-10-22 16:57:29 -03:00
|
|
|
it('should return list of txs', function(done) {
|
|
|
|
|
var txs = [{
|
|
|
|
|
vin: [{
|
|
|
|
|
addr: 'addr_in_1',
|
|
|
|
|
valueSat: 1000
|
|
|
|
|
}],
|
|
|
|
|
vout: [{
|
|
|
|
|
scriptPubKey: {
|
|
|
|
|
addresses: ['addr_out_1'],
|
|
|
|
|
},
|
|
|
|
|
value: '0.00000900',
|
|
|
|
|
}],
|
|
|
|
|
fees: 0.00000100
|
|
|
|
|
}, {
|
|
|
|
|
vin: [{
|
|
|
|
|
addr: 'addr_in_2',
|
|
|
|
|
valueSat: 2000
|
|
|
|
|
}],
|
|
|
|
|
vout: [{
|
|
|
|
|
scriptPubKey: {
|
|
|
|
|
addresses: ['addr_out_2'],
|
|
|
|
|
},
|
|
|
|
|
value: '0.00001900',
|
|
|
|
|
}],
|
|
|
|
|
fees: 0.00000100
|
|
|
|
|
}, {
|
|
|
|
|
vin: [{
|
|
|
|
|
addr: 'addr_in_1',
|
|
|
|
|
valueSat: 3000
|
|
|
|
|
|
|
|
|
|
}],
|
|
|
|
|
vout: [{
|
|
|
|
|
scriptPubKey: {
|
|
|
|
|
addresses: ['addr_out_2'],
|
|
|
|
|
},
|
|
|
|
|
value: '0.00002900',
|
|
|
|
|
|
|
|
|
|
}],
|
|
|
|
|
fees: 0.00000100
|
|
|
|
|
}];
|
|
|
|
|
|
2014-11-17 18:28:01 -03:00
|
|
|
w.blockchain.getTransactions = sinon.stub().yields(null, {
|
|
|
|
|
items: txs,
|
|
|
|
|
totalItems: txs.length,
|
|
|
|
|
});
|
2014-11-28 18:43:22 -03:00
|
|
|
|
2014-12-02 15:18:56 -03:00
|
|
|
sinon.stub(w, 'getAddresses').returns(['addr_in_1', 'addr_out_2']);
|
|
|
|
|
var s = sinon.stub(w.publicKeyRing, 'addressIsOwn');
|
2014-11-28 18:43:22 -03:00
|
|
|
s.withArgs('addr_in_1').returns(true);
|
|
|
|
|
s.withArgs('addr_in_2').returns(false);
|
|
|
|
|
s.withArgs('addr_out_2').returns(true);
|
|
|
|
|
|
|
|
|
|
|
2014-12-02 15:18:56 -03:00
|
|
|
var s2 = sinon.stub(w.publicKeyRing, 'addressIsChange');
|
2014-11-28 18:43:22 -03:00
|
|
|
s2.withArgs('addr_out_1').returns(false);
|
|
|
|
|
s2.withArgs('addr_out_2').returns(false);
|
2014-10-22 16:57:29 -03:00
|
|
|
|
|
|
|
|
w.getTransactionHistory(function(err, res) {
|
|
|
|
|
res.should.exist;
|
2014-11-10 10:45:29 -03:00
|
|
|
res.items.should.exist;
|
|
|
|
|
var items = res.items;
|
|
|
|
|
items.length.should.equal(3);
|
|
|
|
|
items[0].action.should.equal('sent');
|
|
|
|
|
items[0].amountSat.should.equal(900);
|
|
|
|
|
items[1].action.should.equal('received');
|
|
|
|
|
items[1].amountSat.should.equal(1900);
|
|
|
|
|
items[2].action.should.equal('moved');
|
|
|
|
|
items[2].amountSat.should.equal(2900);
|
2014-10-22 16:57:29 -03:00
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
2014-11-10 11:25:31 -03:00
|
|
|
it('should return paginated list of txs', function(done) {
|
|
|
|
|
var txs = [{
|
|
|
|
|
txid: 'id1',
|
|
|
|
|
vin: [{
|
|
|
|
|
addr: 'addr_in_1',
|
|
|
|
|
valueSat: 1000
|
|
|
|
|
}],
|
|
|
|
|
vout: [{
|
|
|
|
|
scriptPubKey: {
|
|
|
|
|
addresses: ['addr_out_1'],
|
|
|
|
|
},
|
|
|
|
|
value: '0.00000900',
|
|
|
|
|
}],
|
|
|
|
|
fees: 0.00000100
|
|
|
|
|
}, {
|
|
|
|
|
txid: 'id2',
|
|
|
|
|
vin: [{
|
|
|
|
|
addr: 'addr_in_2',
|
|
|
|
|
valueSat: 2000
|
|
|
|
|
}],
|
|
|
|
|
vout: [{
|
|
|
|
|
scriptPubKey: {
|
|
|
|
|
addresses: ['addr_out_2'],
|
|
|
|
|
},
|
|
|
|
|
value: '0.00001900',
|
|
|
|
|
}],
|
|
|
|
|
fees: 0.00000100
|
|
|
|
|
}, {
|
|
|
|
|
txid: 'id3',
|
|
|
|
|
vin: [{
|
|
|
|
|
addr: 'addr_in_1',
|
|
|
|
|
valueSat: 3000
|
|
|
|
|
|
|
|
|
|
}],
|
|
|
|
|
vout: [{
|
|
|
|
|
scriptPubKey: {
|
|
|
|
|
addresses: ['addr_out_2'],
|
|
|
|
|
},
|
|
|
|
|
value: '0.00002900',
|
|
|
|
|
|
|
|
|
|
}],
|
|
|
|
|
fees: 0.00000100
|
|
|
|
|
}];
|
|
|
|
|
|
2014-11-17 18:28:01 -03:00
|
|
|
w.blockchain.getTransactions = sinon.stub().yields(null, {
|
2014-11-22 20:00:18 -03:00
|
|
|
items: txs.slice(2, 3),
|
2014-11-17 18:28:01 -03:00
|
|
|
totalItems: txs.length,
|
|
|
|
|
});
|
2014-11-10 11:25:31 -03:00
|
|
|
|
|
|
|
|
w.getTransactionHistory({
|
|
|
|
|
currentPage: 2,
|
|
|
|
|
itemsPerPage: 2
|
|
|
|
|
}, function(err, res) {
|
|
|
|
|
res.should.exist;
|
|
|
|
|
res.nbItems.should.equal(3);
|
|
|
|
|
res.nbPages.should.equal(2);
|
|
|
|
|
res.currentPage.should.equal(2);
|
|
|
|
|
res.items.should.exist;
|
|
|
|
|
res.items.length.should.equal(1);
|
|
|
|
|
res.items[0].txid.should.equal('id3');
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
it('should paginate empty list', function(done) {
|
2014-11-17 18:28:01 -03:00
|
|
|
var txs = [];
|
|
|
|
|
w.blockchain.getTransactions = sinon.stub().yields(null, {
|
|
|
|
|
items: txs,
|
|
|
|
|
totalItems: txs.length,
|
|
|
|
|
});
|
2014-11-10 11:25:31 -03:00
|
|
|
|
|
|
|
|
w.getTransactionHistory({
|
|
|
|
|
currentPage: 2,
|
|
|
|
|
itemsPerPage: 2
|
|
|
|
|
}, function(err, res) {
|
|
|
|
|
res.should.exist;
|
|
|
|
|
res.nbItems.should.equal(0);
|
|
|
|
|
res.nbPages.should.equal(0);
|
|
|
|
|
res.items.should.exist;
|
|
|
|
|
res.items.length.should.equal(0);
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
2014-10-22 16:57:29 -03:00
|
|
|
it('should compute sent amount correctly', function(done) {
|
|
|
|
|
var txs = [{
|
|
|
|
|
vin: [{
|
|
|
|
|
addr: 'addr_in_1',
|
|
|
|
|
valueSat: 3000
|
|
|
|
|
}, {
|
|
|
|
|
addr: 'addr_in_2',
|
|
|
|
|
valueSat: 2000
|
|
|
|
|
}],
|
|
|
|
|
vout: [{
|
|
|
|
|
scriptPubKey: {
|
|
|
|
|
addresses: ['addr_out_1'],
|
|
|
|
|
},
|
|
|
|
|
value: '0.00003900',
|
|
|
|
|
}, {
|
|
|
|
|
scriptPubKey: {
|
|
|
|
|
addresses: ['change'],
|
|
|
|
|
},
|
|
|
|
|
value: '0.00001000',
|
|
|
|
|
}],
|
|
|
|
|
fees: 0.00000100
|
|
|
|
|
}];
|
|
|
|
|
|
2014-11-17 18:28:01 -03:00
|
|
|
w.blockchain.getTransactions = sinon.stub().yields(null, {
|
|
|
|
|
items: txs,
|
|
|
|
|
totalItems: txs.length,
|
|
|
|
|
});
|
2014-11-28 18:43:22 -03:00
|
|
|
|
|
|
|
|
|
2014-12-02 15:18:56 -03:00
|
|
|
sinon.stub(w, 'getAddresses').returns(['addr_in_1', 'addr_in_2', 'change']);
|
|
|
|
|
var s = sinon.stub(w.publicKeyRing, 'addressIsOwn');
|
2014-11-28 18:43:22 -03:00
|
|
|
s.withArgs('addr_in_1').returns(true);
|
|
|
|
|
s.withArgs('addr_in_2').returns(true);
|
|
|
|
|
s.withArgs('change').returns(true);
|
|
|
|
|
|
2014-12-02 15:18:56 -03:00
|
|
|
var s2 = sinon.stub(w.publicKeyRing, 'addressIsChange');
|
2014-11-28 18:43:22 -03:00
|
|
|
s2.withArgs('addr_out_2').returns(false);
|
|
|
|
|
s2.withArgs('change').returns(true);
|
2014-10-22 16:57:29 -03:00
|
|
|
|
|
|
|
|
w.getTransactionHistory(function(err, res) {
|
|
|
|
|
res.should.exist;
|
2014-11-10 10:45:29 -03:00
|
|
|
res.items.should.exist;
|
|
|
|
|
var items = res.items;
|
|
|
|
|
items[0].action.should.equal('sent');
|
|
|
|
|
items[0].amountSat.should.equal(3900);
|
2014-10-22 16:57:29 -03:00
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
it('should compute moved amount correctly', function(done) {
|
|
|
|
|
var txs = [{
|
|
|
|
|
vin: [{
|
|
|
|
|
addr: 'addr_1',
|
|
|
|
|
valueSat: 3000
|
|
|
|
|
}, {
|
|
|
|
|
addr: 'addr_2',
|
|
|
|
|
valueSat: 2000
|
|
|
|
|
}],
|
|
|
|
|
vout: [{
|
|
|
|
|
scriptPubKey: {
|
|
|
|
|
addresses: ['addr_1'],
|
|
|
|
|
},
|
|
|
|
|
value: '0.00003900',
|
|
|
|
|
}, {
|
|
|
|
|
scriptPubKey: {
|
|
|
|
|
addresses: ['change'],
|
|
|
|
|
},
|
|
|
|
|
value: '0.00001000',
|
|
|
|
|
}],
|
|
|
|
|
fees: 0.00000100
|
|
|
|
|
}];
|
|
|
|
|
|
2014-11-17 18:28:01 -03:00
|
|
|
w.blockchain.getTransactions = sinon.stub().yields(null, {
|
|
|
|
|
items: txs,
|
|
|
|
|
totalItems: txs.length,
|
|
|
|
|
});
|
2014-11-28 18:43:22 -03:00
|
|
|
|
2014-12-02 15:18:56 -03:00
|
|
|
sinon.stub(w, 'getAddresses').returns(['addr_in_1', 'addr_in_2', 'change']);
|
|
|
|
|
var s = sinon.stub(w.publicKeyRing, 'addressIsOwn');
|
2014-11-28 18:43:22 -03:00
|
|
|
s.withArgs('addr_1').returns(true);
|
|
|
|
|
s.withArgs('addr_2').returns(true);
|
|
|
|
|
s.withArgs('change').returns(true);
|
|
|
|
|
|
2014-12-02 15:18:56 -03:00
|
|
|
var s2 = sinon.stub(w.publicKeyRing, 'addressIsChange');
|
2014-11-28 18:43:22 -03:00
|
|
|
s2.withArgs('addr_1').returns(false);
|
|
|
|
|
s2.withArgs('change').returns(true);
|
2014-10-22 16:57:29 -03:00
|
|
|
|
|
|
|
|
w.getTransactionHistory(function(err, res) {
|
|
|
|
|
res.should.exist;
|
2014-11-10 10:45:29 -03:00
|
|
|
res.items.should.exist;
|
|
|
|
|
var items = res.items;
|
|
|
|
|
items[0].action.should.equal('moved');
|
|
|
|
|
items[0].amountSat.should.equal(3900);
|
2014-10-22 16:57:29 -03:00
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
2014-10-23 11:38:56 -03:00
|
|
|
it('should assign label when address in address book', function(done) {
|
|
|
|
|
var txs = [{
|
|
|
|
|
vin: [{
|
|
|
|
|
addr: 'addr_in_1',
|
|
|
|
|
valueSat: 3000
|
|
|
|
|
}, {
|
|
|
|
|
addr: 'addr_in_2',
|
|
|
|
|
valueSat: 2000
|
|
|
|
|
}],
|
|
|
|
|
vout: [{
|
|
|
|
|
scriptPubKey: {
|
|
|
|
|
addresses: ['addr_out_1'],
|
|
|
|
|
},
|
|
|
|
|
value: '0.00003900',
|
|
|
|
|
}, {
|
|
|
|
|
scriptPubKey: {
|
|
|
|
|
addresses: ['change'],
|
|
|
|
|
},
|
|
|
|
|
value: '0.00001000',
|
|
|
|
|
}],
|
|
|
|
|
fees: 0.00000100
|
|
|
|
|
}];
|
|
|
|
|
|
2014-11-17 18:28:01 -03:00
|
|
|
w.blockchain.getTransactions = sinon.stub().yields(null, {
|
|
|
|
|
items: txs,
|
|
|
|
|
totalItems: txs.length,
|
|
|
|
|
});
|
2014-10-23 11:38:56 -03:00
|
|
|
|
|
|
|
|
w.addressBook = {
|
|
|
|
|
'addr_out_1': {
|
|
|
|
|
label: 'Address out one'
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
w.getTransactionHistory(function(err, res) {
|
|
|
|
|
res.should.exist;
|
2014-11-10 10:45:29 -03:00
|
|
|
res.items.should.exist;
|
|
|
|
|
res.items[0].labelTo.should.equal('Address out one');
|
2014-10-23 11:38:56 -03:00
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
2014-10-23 12:05:10 -03:00
|
|
|
it('should assign comment from tx proposal if found', function(done) {
|
|
|
|
|
var txs = [{
|
|
|
|
|
txid: 'id1',
|
|
|
|
|
vin: [{
|
|
|
|
|
addr: 'addr_in_1',
|
|
|
|
|
valueSat: 3000
|
|
|
|
|
}, {
|
|
|
|
|
addr: 'addr_in_2',
|
|
|
|
|
valueSat: 2000
|
|
|
|
|
}],
|
|
|
|
|
vout: [{
|
|
|
|
|
scriptPubKey: {
|
|
|
|
|
addresses: ['addr_out_1'],
|
|
|
|
|
},
|
|
|
|
|
value: '0.00003900',
|
|
|
|
|
}, {
|
|
|
|
|
scriptPubKey: {
|
|
|
|
|
addresses: ['change'],
|
|
|
|
|
},
|
|
|
|
|
value: '0.00001000',
|
|
|
|
|
}],
|
|
|
|
|
fees: 0.00000100
|
|
|
|
|
}];
|
2014-10-23 11:38:56 -03:00
|
|
|
|
2014-11-17 18:28:01 -03:00
|
|
|
w.blockchain.getTransactions = sinon.stub().yields(null, {
|
|
|
|
|
items: txs,
|
|
|
|
|
totalItems: txs.length,
|
|
|
|
|
});
|
2014-10-23 12:05:10 -03:00
|
|
|
|
2014-11-26 15:15:12 -03:00
|
|
|
w.txProposals.txps = [{
|
2014-10-23 12:33:55 -03:00
|
|
|
sentTxid: 'id0',
|
2014-10-23 12:05:10 -03:00
|
|
|
comment: 'My comment',
|
2014-11-26 15:15:12 -03:00
|
|
|
rejectedBy: {},
|
|
|
|
|
signedBy: {},
|
|
|
|
|
seenBy: {},
|
2014-10-23 12:05:10 -03:00
|
|
|
}, {
|
2014-10-23 12:33:55 -03:00
|
|
|
sentTxid: 'id1',
|
2014-10-23 12:05:10 -03:00
|
|
|
comment: 'Another comment',
|
2014-11-26 15:15:12 -03:00
|
|
|
rejectedBy: {},
|
|
|
|
|
signedBy: {},
|
|
|
|
|
seenBy: {},
|
|
|
|
|
}];
|
2014-10-23 12:05:10 -03:00
|
|
|
w.getTransactionHistory(function(err, res) {
|
|
|
|
|
res.should.exist;
|
2014-11-10 10:45:29 -03:00
|
|
|
res.items.should.exist;
|
|
|
|
|
res.items[0].comment.should.equal('Another comment');
|
2014-10-23 12:05:10 -03:00
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
2014-10-22 16:57:29 -03:00
|
|
|
});
|
|
|
|
|
|
2014-11-27 10:56:41 -03:00
|
|
|
|
2014-11-25 15:09:51 -03:00
|
|
|
// TODO
|
2014-11-24 11:46:51 -03:00
|
|
|
describe.skip('#onPayProPaymentAck', function() {
|
|
|
|
|
it('should emit', function() {
|
|
|
|
|
var w = cachedCreateW2();
|
2014-11-25 17:44:51 -03:00
|
|
|
sinon.stub(w, 'emitAndKeepAlive');
|
2014-11-24 11:46:51 -03:00
|
|
|
w.onPayProPaymentAck('id', 'data');
|
2014-11-25 15:09:51 -03:00
|
|
|
|
|
|
|
|
w.calledOnce.should.equal(true);
|
|
|
|
|
w.getCall(0).args.should.deep.equal(['paymentACK', 'data']);
|
2014-11-24 11:46:51 -03:00
|
|
|
});
|
|
|
|
|
});
|
2014-10-22 16:57:29 -03:00
|
|
|
|
2014-10-27 13:13:08 -03:00
|
|
|
describe.skip('#read', function() {
|
2014-10-25 17:14:04 -03:00
|
|
|
var network, blockchain;
|
2014-09-29 16:55:45 -03:00
|
|
|
|
2014-10-07 18:33:55 -03:00
|
|
|
beforeEach(function() {
|
|
|
|
|
var s = function() {};
|
|
|
|
|
network = new Network(walletConfig.network);
|
|
|
|
|
blockchain = new Blockchain(walletConfig.blockchain);
|
|
|
|
|
});
|
2014-09-29 16:55:45 -03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
it('should fail to read an unexisting wallet', function(done) {
|
|
|
|
|
|
2014-10-07 18:33:55 -03:00
|
|
|
Wallet.read('123', {
|
|
|
|
|
networkOpts: {},
|
|
|
|
|
blockchainOpts: {},
|
|
|
|
|
}, function(err, w) {
|
2014-09-29 16:55:45 -03:00
|
|
|
err.toString().should.contain('WNOTFOUND');
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should not read a corrupted wallet', function(done) {
|
|
|
|
|
|
2014-10-07 18:33:55 -03:00
|
|
|
Wallet.read('123', {
|
|
|
|
|
networkOpts: {},
|
|
|
|
|
blockchainOpts: {},
|
|
|
|
|
}, function(err, w) {
|
2014-09-29 16:55:45 -03:00
|
|
|
err.toString().should.contain('WERROR');
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should read a wallet', function(done) {
|
2014-10-07 18:33:55 -03:00
|
|
|
Wallet.read('123', {
|
|
|
|
|
networkOpts: {},
|
|
|
|
|
blockchainOpts: {},
|
|
|
|
|
}, function(err, w) {
|
2014-09-29 16:55:45 -03:00
|
|
|
should.not.exist(err);
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
2014-09-30 08:09:39 -03:00
|
|
|
|
|
|
|
|
it('should be able to import unencrypted legacy wallet TxProposal: v0', function(done) {
|
2014-10-07 18:33:55 -03:00
|
|
|
Wallet.read('123', {
|
|
|
|
|
networkOpts: {},
|
|
|
|
|
blockchainOpts: {},
|
|
|
|
|
}, function(err, w) {
|
2014-09-30 08:09:39 -03:00
|
|
|
should.exist(w);
|
|
|
|
|
w.id.should.equal('55d4bd062d32f90a');
|
|
|
|
|
should.exist(w.publicKeyRing.getCopayerId);
|
|
|
|
|
should.exist(w.txProposals.toObj());
|
|
|
|
|
should.exist(w.privateKey.toObj());
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should be able to import simple 1-of-1 encrypted legacy testnet wallet', function(done) {
|
|
|
|
|
|
2014-10-07 18:33:55 -03:00
|
|
|
Wallet.read('123', {
|
|
|
|
|
networkOpts: {},
|
|
|
|
|
blockchainOpts: {},
|
|
|
|
|
}, function(err, w) {
|
2014-09-30 08:09:39 -03:00
|
|
|
should.exist(w);
|
2014-11-30 00:31:17 -03:00
|
|
|
w.isComplete().should.equal(true);
|
2014-09-30 08:09:39 -03:00
|
|
|
var wo = w.toObj();
|
|
|
|
|
wo.opts.id.should.equal('48ba2f1ffdfe9708');
|
|
|
|
|
wo.opts.spendUnconfirmed.should.equal(true);
|
|
|
|
|
wo.opts.requiredCopayers.should.equal(1);
|
|
|
|
|
wo.opts.totalCopayers.should.equal(1);
|
|
|
|
|
wo.opts.name.should.equal('pepe wallet');
|
|
|
|
|
wo.opts.version.should.equal('0.4.7');
|
|
|
|
|
wo.publicKeyRing.walletId.should.equal('48ba2f1ffdfe9708');
|
|
|
|
|
wo.publicKeyRing.networkName.should.equal('testnet');
|
|
|
|
|
wo.publicKeyRing.requiredCopayers.should.equal(1);
|
|
|
|
|
wo.publicKeyRing.totalCopayers.should.equal(1);
|
|
|
|
|
wo.publicKeyRing.indexes.length.should.equal(2);
|
|
|
|
|
JSON.stringify(wo.publicKeyRing.indexes[0]).should.equal('{"copayerIndex":2147483647,"changeIndex":0,"receiveIndex":1}');
|
|
|
|
|
JSON.stringify(wo.publicKeyRing.indexes[1]).should.equal('{"copayerIndex":0,"changeIndex":0,"receiveIndex":1}');
|
|
|
|
|
wo.publicKeyRing.copayersExtPubKeys.length.should.equal(1);
|
|
|
|
|
wo.publicKeyRing.copayersExtPubKeys[0].should.equal('tpubD9SGoP7CXsqSKTiQxCZSCpicDcophqnE4yuqjfw5M9tAR3fSjT9GDGwPEUFCN7SSmRKGDLZgKQePYFaLWyK32akeSan45TNTd8sgef9Ymh6');
|
|
|
|
|
wo.privateKey.extendedPrivateKeyString.should.equal('tprv8ZgxMBicQKsPfQCscb7CtJKzixxcVSyrCVcfr3WCFbtT8kYTzNubhjQ5R7AuYJgPCcSH4R8T34YVxeohKGhAB9wbB4eFBbQFjUpjGCqptHm');
|
|
|
|
|
wo.privateKey.networkName.should.equal('testnet');
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
});
|
2014-09-29 16:55:45 -03:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
2014-09-30 08:09:39 -03:00
|
|
|
|
2014-10-28 15:56:03 -03:00
|
|
|
var legacyO = '{"opts":{"id":"55d4bd062d32f90a","spendUnconfirmed":true,"requiredCopayers":2,"totalCopayers":2,"name":"xcvzxcv","version":"0.3.2"},"networkNonce":"53d25e8600000009","networkNonces":[],"publicKeyRing":{"walletId":"55d4bd062d32f90a","networkName":"testnet","requiredCopayers":2,"totalCopayers":2,"indexes":[{"copayerIndex":2147483647,"changeIndex":0,"receiveIndex":0},{"copayerIndex":0,"changeIndex":4,"receiveIndex":2},{"copayerIndex":1,"changeIndex":5,"receiveIndex":2}],"copayersExtPubKeys":["tpubD94LTzAUiW99mpA59nyf6fAHh4xKGmnwbgCV4gU2bRpeN9CRiMSurqme22px5NmJAo6FdcdH883Zu98VbqyhesCJ86kUEjH3Zpufy5FfcaC","tpubDA2U9H6LkRHDRbRxHBp4VTbxPc7JqsvtcLxrE5QJF8z1iT6hMJ1pXSVf57GWRcxXutYvpoXRurDVGsscJauMtnJBkYAWBVExYmm91XQE2zz"],"nicknameFor":{"02c7b87033e4357d8afc6ab7fe31fff054772ea6251f0d9c8a835b1c1ac74f6fba":"asdf","02b0c868a3889cd0cfc0e7fef9eaa6d85d7cf6f7573ae5c9d1d13645d22e2eb7e5":"qwerqw"},"publicKeysCache":{"m/0/0/0":["028a4b63f26253f3a8731577b8e1ee480950ad5833ebbf106fe3463bfc07cc3b90","0332efa054c08cb77506a35ee0762cb7156f244566703ec08e433568ec0397bec8"],"m/1/0/0":["0220ad514cf593d0c3905d3bb49bc5767a9410823bf9b77ea5ef2cf1d1016d77a8","02fd42cf66f1dbdc7bbb9ae09aecea72df479ffe5a0c4641301067e331d12e416d"],"m/1/0/1":["0315f7868eaf1f9b7127e3f7e0222c5e473eea003e34700f4758b6873c525d6723","02a2e8ed5e90dd39e3842fc790e06178997dbca319987f365317589e2a71a93658"],"m/0/1/0":["0244a25a0b97b26707fd855c15b046b901be85a3b70a781d0678608e633440eeca","0358cdcbc528ddfb7173b0dab283f702be82546ff031e4a832a7270080cb875959"],"m/0/1/1":["025c9b49bdf17d97bd82ea1b87793082f857247f0f9b999937a166ec994bb1b41f","020389327ee8ae7d0ee3f8187842d23a4070bdd8a27c0bcddd05d80ef39009253d"],"m/1/1/0":["02fd0e7c62b7b58d1ea7bb4cb84d53b019df99d3703a42aed73a2cfa15f3af5d08","0355a15912e76072ef50e6643376b8a9da8422ed4f8ea07b1d84d4989be5a39b2e"],"m/1/1/1":["03bc3e1f4db32efd8eb1fd44a1665938d59628429c67e1e8b7054ab5717f4e6750","03c4c817b633ac31f44f16f390af831d35f7d98744a52a0f23e9598967342255f8"],"m/1/1/2":["02826fe7e9da408480ddeb1d4414c5100b350f862ca718e27122681e1a0ca35077","02bd25af907bb3edbf6b2cd1ea90eaa92cc93ec47bea7d339af44c1d2c05708e99"],"m/0/1/2":["0337a1a70364b94745d6e26d2d28919cf528304f52765f12ef43e3d6da0a6c8dc0","039d83db9aa43e6e00e0304e6971b6079d79dc12d8d55ce2e6fc24a52ba8d41329"],"m/0/0/1":["0359c6d0d0d31f83301169901a6ffad9535f14014b5ab3b43561dbb2436a7b8138","037d06f713f13a11967fd5edca265ff4c77528693a712c482256505693e4890d93"],"m/1/1/3":["02600e5c41670773a213a4cb58c8f2fa3e83840784bc7f0b56925e1075e06632c2","036d01867af5f61371151ef7d9026fa0400a623f6924e404ee0b856625268972f9"],"m/0/1/3":["03e5a9b039b187ca8e065627df402e4a5b196b94198542da7036879de08be63d2d","0304f3e0b70f696d80e5785dc7747d6dcb55ba24c31f2d80bf184b4e582e6b47fc"],"m/1/1/4":["03741afa5bd50d6ba5801064c810fae84f6a4557d6a88ddc8591d0d4eb68a8fc41","0214dd6ce6073b05999fb887098ca6f7e1d0b4fdc0760557786907df353df90d1c"],"m/2147483647/1/0":["033e072a53ea835763a03c66e35c35384736210a1bb7d7ee6d9a3e109e82426b30","02e37b5570c053da8a8ee587be86fc629775c4db890aba2745ccc4e4dcc8c31041"],"m/2147483647/1/1":["0228a6de42ef421c263d1efd9f28d9a7d15a261995028a24eff6b9f1c3fc46e6bf","0226cff885cb0d607cc9cf69a7608316eb3fb2ec344c0c9956246ba776116fc396"],"m/2147483647/1/2":["034fe2a8f0b98445eb5810fe36572ad2f64ed9bf64dc9de624f99c0142cb07c682","02f2c5c758e32293f5c193fd69afadbba83abafb397db01e6f2b447690e900475a"],"m/2147483647/1/3":["02b25ef9434446c51f10678f787e4913de582e34d164bd3b06af7732c5476df1a8","025d51a1efd59bcff22ee2e0af61b21a7ba5f639e20dfdf25690e926005177dd0c"],"m/2147483647/1/4":["03e5734e1d29b2f684d0446b7a2ffbd0ba8952570a502d0d14b1efd8f24b61be53","0258fc28a324848d8d0154e8614815e35c668d274a8f01957bb99aab8dc8f386c0"],"m/2147483647/1/5":["021f9e775246765e1cfba0ae453b4eae6cd4ae5a57a09c319edbe89d4dbbf23be3","02857f66571a1c3eb9e72d22ae88e734c03d448bced4dcfd345c2059468124c741"],"m/2147483647/1/6":["02c072f329391a25255dc6452e5f5220966869dbf736ba8a8c3ae9d273a84bc3fd","030920a8b8e88c4db2871a7df0878a86cf0695f6d96bb50c701c3454f3df25176a"],"m/2147483647/1/7":["036bf329fc19bce10cf1999fae5bfa80290ff7b44776b49c7b0dc9eec6cffcfa21","03955a549875b
|
2014-09-30 08:09:39 -03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-10-28 15:56:03 -03:00
|
|
|
var legacy1 = '{"opts":{"id":"48ba2f1ffdfe9708","spendUnconfirmed":true,"requiredCopayers":1,"totalCopayers":1,"name":"pepe wallet","version":"0.4.7"},"networkNonce":"5405f06b00000001","networkNonces":[],"publicKeyRing":{"walletId":"48ba2f1ffdfe9708","networkName":"testnet","requiredCopayers":1,"totalCopayers":1,"indexes":[{"copayerIndex":2147483647,"changeIndex":0,"receiveIndex":1},{"copayerIndex":0,"changeIndex":0,"receiveIndex":1}],"copayersExtPubKeys":["tpubD9SGoP7CXsqSKTiQxCZSCpicDcophqnE4yuqjfw5M9tAR3fSjT9GDGwPEUFCN7SSmRKGDLZgKQePYFaLWyK32akeSan45TNTd8sgef9Ymh6"],"nicknameFor":{}},"txProposals":{"txps":[],"walletId":"48ba2f1ffdfe9708","networkName":"testnet"},"privateKey":{"extendedPrivateKeyString":"tprv8ZgxMBicQKsPfQCscb7CtJKzixxcVSyrCVcfr3WCFbtT8kYTzNubhjQ5R7AuYJgPCcSH4R8T34YVxeohKGhAB9wbB4eFBbQFjUpjGCqptHm","networkName":"testnet"},"addressBook":{}}';
|
2014-09-30 08:09:39 -03:00
|
|
|
|
|
|
|
|
|
2014-09-29 10:18:47 -03:00
|
|
|
// DATA
|
2014-11-30 18:55:15 -03:00
|
|
|
var o = '{"opts":{"id":"dbfe10c3fae71cea", "spendUnconfirmed":1,"requiredCopayers":3,"totalCopayers":5,"version":"0.0.5","networkName":"testnet"},"networkNonce":"0000000000000001","networkNonces":[],"publicKeyRing":{ "cache": { "addressToPath": {}}, "walletId":"dbfe10c3fae71cea","networkName":"testnet","requiredCopayers":3,"totalCopayers":5,"indexes":[{"copayerIndex":2,"changeIndex":0,"receiveIndex":0}],"copayersExtPubKeys":["tpubD6NzVbkrYhZ4YGK8ZhZ8WVeBXNAAoTYjjpw9twCPiNGrGQYFktP3iVQkKmZNiFnUcAFMJRxJVJF6Nq9MDv2kiRceExJaHFbxUCGUiRhmy97","tpubD6NzVbkrYhZ4YKGDJkzWdQsQV3AcFemaQKiwNhV4RL8FHnBFvinidGdQtP8RKj3h34E65RkdtxjrggZYqsEwJ8RhhN2zz9VrjLnrnwbXYNc","tpubD6NzVbkrYhZ4YkDiewjb32Pp3Sz9WK2jpp37KnL7RCrHAyPpnLfgdfRnTdpn6DTWmPS7niywfgWiT42aJb1J6CjWVNmkgsMCxuw7j9DaGKB","tpubD6NzVbkrYhZ4XEtUAz4UUTWbprewbLTaMhR8NUvSJUEAh4Sidxr6rRPFdqqVRR73btKf13wUjds2i8vVCNo8sbKrAnyoTr3o5Y6QSbboQjk","tpubD6NzVbkrYhZ4Yj9AAt6xUVuGPVd8jXCrEE6V2wp7U3PFh8jYYvVad31b4VUXEYXzSnkco4fktu8r4icBsB2t3pCR3WnhVLedY2hxGcPFLKD"],"nicknameFor":{}},"txProposals":{"txps":[],"walletId":"dbfe10c3fae71cea","networkName":"testnet"},"privateKey":{"extendedPrivateKeyString":"tprv8ZgxMBicQKsPeoHLg3tY75z4xLeEe8MqAXLNcRA6J6UTRvHV8VZTXznt9eoTmSk1fwSrwZtMhY3XkNsceJ14h6sCXHSWinRqMSSbY8tfhHi","networkName":"testnet"},"addressBook":{},"settings":{"unitName":"BTC","unitToSatoshi":100000000,"unitDecimals":8,"alternativeName":"Argentine Peso","alternativeIsoCode":"ARS"}}';
|
2014-09-29 10:18:47 -03:00
|
|
|
|
2014-09-03 13:17:59 -03:00
|
|
|
});
|
2014-11-25 09:45:44 -03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var x509 = {
|
2014-11-25 13:50:19 -03:00
|
|
|
priv: 'LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBeFRKdUsyYUdMbjFkWEpLRGg0TXdQTFVrbDNISTVwR25HNWFjNGwvMGlobXE4Y3dDCitGVlBnWk1TNTlheWtpc0IrekM3dnR2a0prL2J2K0JTT1g3b3hkSXN1TDNkS1FGcHVYWFZmcmRiOTV3WW40TSsKL25qRWhYTWxoVk1IL09DaUFnOUpLaFRLV0w2R1JXWkFBaEE3bEJSaGdTTkRUaVRDNTFDYmlLN3hBNnBONCt0UQpIeG9tSlBYclpSa2JCMmtsT2ZXd2J2OTNZM0oxS0ZEK2kwUE1RSEx3N3JoRXVteEM5MytISFVWWVZIN0gxVFBaCkgxYmRVSkowMmdRZXlsSnNzWUNKeWRaUHpOVC96dXRzL0tKV2RSdjVseHdHOXU5dE1OTWdoSmJtQWFNa01HaSsKbzdQTkV5UDNxSEZyWXBZaHM1cHFMSE1STkI3OFFNOUllTmpMRndJREFRQUJBb0lCQVFERVJyalBiQUdjbmwxaAorZGIrOTczNGZ0aElBUkpWSko1dTRFK1JKcThSRWhGTEVLUFlKNW0yUC94dVZBMXpYV2xnYXhaRUZ6d1VRaUpZCjdsOEpLVjlwSHhReVlaQ1M4dndYZzhpWGtzdndQaWRvQmN1YW4vd0RWQ1FCZXk2VkxjVXpSYUd1Ui9sTHNYK1YKN2Z0QjBvUnFsSXFrYmNQZE1NdnFUeG93UnVoUG11Q3JWVGpPNHBiTnFuU09OUExPaUovRkFYYjJwZnpGZnBCUgpHeCtFTW16d2UrSEZuSkJHRGhIWjk5bm4vVEJmYUp6TlZDcURZLzNid3o1WDdIUU5ZN1QrSnlUVUZzZVE5NHhzCnpya2lidGRmVGNUanB1K1VoWm80c1p6Q3IrZkhHWm9FOUdEUHF0ZDRnQ3ByazRFS0pzbXFCRVN4QlhTRGhZZ04KOXBVRDM4c1pBb0dCQU9yZkRqdDZaL0ZDamFuVThXek5GaWYrOVQxQTJ4b013RDVWU2xNdVJyWW1HbGZyMEM5TQpmMUVvZ2l2dVRrYnA3cmtnZFRhWVRTYndmTnFaQkt4Y3R5YzdCaGRwWnhERVdKa2Z5cThxVngvem1Cek1JK1ZzCjJLYi9hcHZXcmJlb3NET0NyeUg1YzhKc1VUOXhUWDNYYnhFanlPSlFCU1lHRE1qUHlKNkU5czZMQW9HQkFOYnYKd2d0S2Nra0tLbDJhNXZzaGR2RENnNnFLL1FnT20vNktUSlVKRVNqaHoydFIrZlBWUjcwVEg5UmhoVFJscERXQgpCd3oyU2NCc1RRNDIvTGsxRnkyMFQvck12S3VmSEw1VE1BNGZ6NWRxMUxIbmN6ejZVazVnWEtBT09rUjlVdVhpClR0eTNoREcyQkM4Nk1LTVJ4SjUxRWJxam94d0VSMTAwU2FuTVBmTWxBb0dBSUhLY1pyOHNhUHBHMC9XbFBPREEKZE5vV1MxWVFidkxnQkR5SVBpR2doejJRV2lFcjY3em53ZkNVdXpqNiszVUtFKzFXQkNyYVRjemZrdHVjOTZyLwphcDRPNDJFZWFnU1dNT0ZoZ1AyYWQ4R1JmRGovcEl4N0NlY3pkVUFkVThnc1A1R0lYR3M0QU40eUEwL0Y0dUxHCloxbklRT3ZKS2syZnFvWjZNdHd2dEswQ2dZRUFnSjdGTGVDRTkzUmYyZGdDZFRHWGJZZlpKc3M1bEFLNkV0NUwKNmJ1ZFN5dWw1Z0VPWkgyekNsQlJjZFJSMUFNbSt1V1ZoSW8xcERLckFlQ2g1MnIvemRmakxLQXNIejkrQWQ3aQpHUEdzVmw0Vm5jaDFTMzQ0bHJKUGUzQklLZ2djL1hncDNTYnNzcHJMY2orT0wyZElrOUpXbzZ1Y3hmMUJmMkwwCjJlbGhBUWtDZ1lCWHN5elZWL1pKcVhOcFdDZzU1TDNVRm9UTHlLU3FsVktNM1dpRzVCS240QWF6VkNITCtHUVUKeHd4U2dSOWZRNEludStyUHJOM0lteWswbEtQR0Y5U3pDUlJUaUpGUjcyc05xbE82bDBWOENXUkFQVFBKY2dxVgoxVThOSEs4YjNaaUlvR0orbXNOenBkeHJqNjJIM0E2K1krQXNOWTRTbVVUWEg5eWpnK251a2c9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=',
|
|
|
|
|
pub: 'LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF4VEp1SzJhR0xuMWRYSktEaDRNdwpQTFVrbDNISTVwR25HNWFjNGwvMGlobXE4Y3dDK0ZWUGdaTVM1OWF5a2lzQit6Qzd2dHZrSmsvYnYrQlNPWDdvCnhkSXN1TDNkS1FGcHVYWFZmcmRiOTV3WW40TSsvbmpFaFhNbGhWTUgvT0NpQWc5SktoVEtXTDZHUldaQUFoQTcKbEJSaGdTTkRUaVRDNTFDYmlLN3hBNnBONCt0UUh4b21KUFhyWlJrYkIya2xPZld3YnY5M1kzSjFLRkQraTBQTQpRSEx3N3JoRXVteEM5MytISFVWWVZIN0gxVFBaSDFiZFVKSjAyZ1FleWxKc3NZQ0p5ZFpQek5UL3p1dHMvS0pXCmRSdjVseHdHOXU5dE1OTWdoSmJtQWFNa01HaStvN1BORXlQM3FIRnJZcFloczVwcUxITVJOQjc4UU05SWVOakwKRndJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==',
|
|
|
|
|
der: 'MIIDBjCCAe4CCQDI2qWdA3/VpDANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMB4XDTE0MDcxNjAxMzM1MVoXDTE1MDcxNjAxMzM1MVowRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMUybitmhi59XVySg4eDMDy1JJdxyOaRpxuWnOJf9IoZqvHMAvhVT4GTEufWspIrAfswu77b5CZP27/gUjl+6MXSLLi93SkBabl11X63W/ecGJ+DPv54xIVzJYVTB/zgogIPSSoUyli+hkVmQAIQO5QUYYEjQ04kwudQm4iu8QOqTePrUB8aJiT162UZGwdpJTn1sG7/d2NydShQ/otDzEBy8O64RLpsQvd/hx1FWFR+x9Uz2R9W3VCSdNoEHspSbLGAicnWT8zU/87rbPyiVnUb+ZccBvbvbTDTIISW5gGjJDBovqOzzRMj96hxa2KWIbOaaixzETQe/EDPSHjYyxcCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAL6AMMfC3TlRcmsIgHxjVD4XYtISlldnrn2X9zvFbJKCpNy8XQQosQxrhyfzPHQKjlS2L/KCGMnjx9QkYD2Hlp1MJ1uVv9888th/gcZOv3Or3hQyi5K1Sh5xCG+69lUOqUEGu9B4irsqoFomQVbQolSy+t4apdJi7kuEDwFDk4gZiVEfsuX+naN5a6pCnWnhX1Vf4fKwfkLobKKXm2zQVsjxlwBAqOEmJGDLoRMXH56qJnEZ/dqsczaJOHQSi9mFEHL0r5rsEDTT5AVxdnBfNnyGaCH7/zANEko+FGBj1JdJaJgFTXdbxDoyoPTPD+LJqSK5XYToo46y/T0u9CLveNA==',
|
|
|
|
|
pem: 'LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURCakNDQWU0Q0NRREkycVdkQTMvVnBEQU5CZ2txaGtpRzl3MEJBUVVGQURCRk1Rc3dDUVlEVlFRR0V3SkIKVlRFVE1CRUdBMVVFQ0F3S1UyOXRaUzFUZEdGMFpURWhNQjhHQTFVRUNnd1lTVzUwWlhKdVpYUWdWMmxrWjJsMApjeUJRZEhrZ1RIUmtNQjRYRFRFME1EY3hOakF4TXpNMU1Wb1hEVEUxTURjeE5qQXhNek0xTVZvd1JURUxNQWtHCkExVUVCaE1DUVZVeEV6QVJCZ05WQkFnTUNsTnZiV1V0VTNSaGRHVXhJVEFmQmdOVkJBb01HRWx1ZEdWeWJtVjAKSUZkcFpHZHBkSE1nVUhSNUlFeDBaRENDQVNJd0RRWUpLb1pJaHZjTkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQgpBTVV5Yml0bWhpNTlYVnlTZzRlRE1EeTFKSmR4eU9hUnB4dVduT0pmOUlvWnF2SE1BdmhWVDRHVEV1ZldzcElyCkFmc3d1NzdiNUNaUDI3L2dVamwrNk1YU0xMaTkzU2tCYWJsMTFYNjNXL2VjR0orRFB2NTR4SVZ6SllWVEIvemcKb2dJUFNTb1V5bGkraGtWbVFBSVFPNVFVWVlFalEwNGt3dWRRbTRpdThRT3FUZVByVUI4YUppVDE2MlVaR3dkcApKVG4xc0c3L2QyTnlkU2hRL290RHpFQnk4TzY0Ukxwc1F2ZC9oeDFGV0ZSK3g5VXoyUjlXM1ZDU2ROb0VIc3BTCmJMR0FpY25XVDh6VS84N3JiUHlpVm5VYitaY2NCdmJ2YlREVElJU1c1Z0dqSkRCb3ZxT3p6Uk1qOTZoeGEyS1cKSWJPYWFpeHpFVFFlL0VEUFNIall5eGNDQXdFQUFUQU5CZ2txaGtpRzl3MEJBUVVGQUFPQ0FRRUFMNkFNTWZDMwpUbFJjbXNJZ0h4alZENFhZdElTbGxkbnJuMlg5enZGYkpLQ3BOeThYUVFvc1F4cmh5ZnpQSFFLamxTMkwvS0NHCk1uang5UWtZRDJIbHAxTUoxdVZ2OTg4OHRoL2djWk92M09yM2hReWk1SzFTaDV4Q0crNjlsVU9xVUVHdTlCNGkKcnNxb0ZvbVFWYlFvbFN5K3Q0YXBkSmk3a3VFRHdGRGs0Z1ppVkVmc3VYK25hTjVhNnBDblduaFgxVmY0Zkt3ZgprTG9iS0tYbTJ6UVZzanhsd0JBcU9FbUpHRExvUk1YSDU2cUpuRVovZHFzY3phSk9IUVNpOW1GRUhMMHI1cnNFCkRUVDVBVnhkbkJmTm55R2FDSDcvekFORWtvK0ZHQmoxSmRKYUpnRlRYZGJ4RG95b1BUUEQrTEpxU0s1WFlUb28KNDZ5L1QwdTlDTHZlTkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg=='
|
2014-11-25 09:45:44 -03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
x509.priv = new Buffer(x509.priv, 'base64');
|
|
|
|
|
x509.pub = new Buffer(x509.pub, 'base64');
|
|
|
|
|
x509.der = new Buffer(x509.der, 'base64');
|
|
|
|
|
x509.pem = new Buffer(x509.pem, 'base64');
|
|
|
|
|
|
2014-11-25 10:59:49 -03:00
|
|
|
var PP = {};
|
|
|
|
|
|
2014-11-25 09:45:44 -03:00
|
|
|
PP.outs = [{
|
|
|
|
|
address: 'mkYn9qmYwMZfovTb6cd7yCGeNozqUyyhK7',
|
|
|
|
|
amountSatStr: '3000'
|
|
|
|
|
}];
|
2014-11-25 10:59:49 -03:00
|
|
|
|
|
|
|
|
PP.merchant_data = {
|
|
|
|
|
request_url: 'url123',
|
|
|
|
|
outs: PP.outs,
|
|
|
|
|
total: PP.outs[0].amountSatStr,
|
|
|
|
|
pr: {
|
|
|
|
|
pd: {
|
|
|
|
|
payment_url: 'url123'
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-11-25 09:45:44 -03:00
|
|
|
PP.getRequest = function() {
|
|
|
|
|
|
|
|
|
|
var uid = 0;
|
|
|
|
|
|
|
|
|
|
var outputs = [];
|
|
|
|
|
|
|
|
|
|
[2000, 1000].forEach(function(value) {
|
|
|
|
|
var po = new PayPro();
|
|
|
|
|
po = po.makeOutput();
|
|
|
|
|
// number of satoshis to be paid
|
|
|
|
|
po.set('amount', value);
|
|
|
|
|
|
|
|
|
|
// TODO use bitcore / script!!
|
|
|
|
|
// a TxOut script where the payment should be sent. similar to OP_CHECKSIG
|
2014-11-25 13:29:03 -03:00
|
|
|
var addr = new bitcore.Address(PP.outs[0].address);
|
|
|
|
|
po.set('script', addr.getScriptPubKey().getBuffer());
|
2014-11-25 09:45:44 -03:00
|
|
|
outputs.push(po.message);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Payment Details
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
var mdata = new Buffer([0]);
|
|
|
|
|
uid++;
|
|
|
|
|
if (uid > 0xffff) {
|
|
|
|
|
throw new Error('UIDs bigger than 0xffff not supported.');
|
|
|
|
|
} else if (uid > 0xff) {
|
|
|
|
|
mdata = new Buffer([(uid >> 8) & 0xff, (uid >> 0) & 0xff])
|
|
|
|
|
} else {
|
|
|
|
|
mdata = new Buffer([0, uid])
|
|
|
|
|
}
|
|
|
|
|
var now = Date.now() / 1000 | 0;
|
|
|
|
|
var pd = new PayPro();
|
|
|
|
|
pd = pd.makePaymentDetails();
|
|
|
|
|
pd.set('network', 'test');
|
|
|
|
|
pd.set('outputs', outputs);
|
|
|
|
|
pd.set('time', now);
|
|
|
|
|
pd.set('expires', now + 60 * 60 * 24);
|
|
|
|
|
pd.set('memo', 'Hello, this is the server, we would like some money.');
|
|
|
|
|
pd.set('payment_url', 'https://pay_url');
|
|
|
|
|
pd.set('merchant_data', mdata);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* PaymentRequest
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
var cr = new PayPro();
|
|
|
|
|
cr = cr.makeX509Certificates();
|
|
|
|
|
cr.set('certificate', [x509.der]);
|
|
|
|
|
|
|
|
|
|
// We send the PaymentRequest to the customer
|
|
|
|
|
var pr = new PayPro();
|
|
|
|
|
pr = pr.makePaymentRequest();
|
|
|
|
|
pr.set('payment_details_version', 1);
|
|
|
|
|
pr.set('pki_type', 'x509+sha256');
|
|
|
|
|
pr.set('pki_data', cr.serialize());
|
|
|
|
|
pr.set('serialized_payment_details', pd.serialize());
|
|
|
|
|
pr.sign(x509.priv);
|
|
|
|
|
|
|
|
|
|
return pr.serialize();
|
|
|
|
|
};
|
|
|
|
|
PP.processPayment = function(payment) {
|
|
|
|
|
body = PayPro.Payment.decode(payment);
|
|
|
|
|
var pay = new PayPro();
|
|
|
|
|
pay = pay.makePayment(body);
|
|
|
|
|
var merchant_data = pay.get('merchant_data');
|
|
|
|
|
var transactions = pay.get('transactions');
|
|
|
|
|
var refund_to = pay.get('refund_to');
|
|
|
|
|
var memo = pay.get('memo');
|
|
|
|
|
|
|
|
|
|
// We send this to the customer after receiving a Payment
|
|
|
|
|
// Then we propogate the transaction through bitcoin network
|
|
|
|
|
var ack = new PayPro();
|
|
|
|
|
ack = ack.makePaymentACK();
|
|
|
|
|
ack.set('payment', pay.message);
|
|
|
|
|
ack.set('memo', 'Thank you for your payment!');
|
|
|
|
|
|
|
|
|
|
ack = ack.serialize();
|
|
|
|
|
|
|
|
|
|
transactions = transactions.map(function(tx) {
|
|
|
|
|
tx.buffer = new Buffer(new Uint8Array(tx.buffer));
|
|
|
|
|
tx.buffer = tx.buffer.slice(tx.offset, tx.limit);
|
|
|
|
|
var ptx = new bitcore.Transaction();
|
|
|
|
|
ptx.parse(tx.buffer);
|
|
|
|
|
return ptx;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return ack;
|
|
|
|
|
};
|