mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-19 19:55:51 +00:00
Add multisignature support
This commit is contained in:
@@ -183,20 +183,20 @@ describe('RippleAPI', function() {
|
||||
|
||||
it('prepareSettings', function() {
|
||||
return this.api.prepareSettings(
|
||||
address, requests.prepareSettings, instructions).then(
|
||||
address, requests.prepareSettings.domain, instructions).then(
|
||||
_.partial(checkResult, responses.prepareSettings.flags, 'prepare'));
|
||||
});
|
||||
|
||||
it('prepareSettings - no maxLedgerVersion', function() {
|
||||
return this.api.prepareSettings(
|
||||
address, requests.prepareSettings, {maxLedgerVersion: null}).then(
|
||||
address, requests.prepareSettings.domain, {maxLedgerVersion: null}).then(
|
||||
_.partial(checkResult, responses.prepareSettings.noMaxLedgerVersion,
|
||||
'prepare'));
|
||||
});
|
||||
|
||||
it('prepareSettings - no instructions', function() {
|
||||
return this.api.prepareSettings(
|
||||
address, requests.prepareSettings).then(
|
||||
address, requests.prepareSettings.domain).then(
|
||||
_.partial(
|
||||
checkResult,
|
||||
responses.prepareSettings.noInstructions,
|
||||
@@ -244,6 +244,13 @@ describe('RippleAPI', function() {
|
||||
'prepare'));
|
||||
});
|
||||
|
||||
it('prepareSettings - set signers', function() {
|
||||
const settings = requests.prepareSettings.signers;
|
||||
return this.api.prepareSettings(address, settings, instructions).then(
|
||||
_.partial(checkResult, responses.prepareSettings.signers,
|
||||
'prepare'));
|
||||
});
|
||||
|
||||
it('prepareSuspendedPaymentCreation', function() {
|
||||
const localInstructions = _.defaults({
|
||||
maxFee: '0.000012'
|
||||
@@ -312,6 +319,14 @@ describe('RippleAPI', function() {
|
||||
schemaValidator.schemaValidate('sign', result);
|
||||
});
|
||||
|
||||
it('sign - signAs', function() {
|
||||
const txJSON = requests.sign.signAs;
|
||||
const secret = 'snoPBrXtMeMyMHUVTgbuqAfg1SUTb';
|
||||
const signature = this.api.sign(JSON.stringify(txJSON), secret,
|
||||
{signAs: 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh'});
|
||||
assert.deepEqual(signature, responses.sign.signAs);
|
||||
});
|
||||
|
||||
it('submit', function() {
|
||||
return this.api.submit(responses.sign.normal.signedTransaction).then(
|
||||
_.partial(checkResult, responses.submit, 'submit'));
|
||||
@@ -326,6 +341,11 @@ describe('RippleAPI', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('combine', function() {
|
||||
const combined = this.api.combine(requests.combine.setDomain);
|
||||
checkResult(responses.combine.single, 'sign', combined);
|
||||
});
|
||||
|
||||
describe('RippleAPI', function() {
|
||||
|
||||
it('getBalances', function() {
|
||||
@@ -1255,7 +1275,7 @@ describe('RippleAPI - offline', function() {
|
||||
it('prepareSettings and sign', function() {
|
||||
const api = new RippleAPI();
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV';
|
||||
const settings = requests.prepareSettings;
|
||||
const settings = requests.prepareSettings.domain;
|
||||
const instructions = {
|
||||
sequence: 23,
|
||||
maxLedgerVersion: 8820051,
|
||||
|
||||
2
test/fixtures/requests/combine.json
vendored
Normal file
2
test/fixtures/requests/combine.json
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
[ "12000322800000002400000004201B000000116840000000000F42407300770B6578616D706C652E636F6D811407C532442A675C881BA1235354D4AB9D023243A6F3E0107321026C784C1987F83BACBF02CD3E484AFC84ADE5CA6B36ED4DCA06D5BA233B9D382774473045022100E484F54FF909469FA2033E22EFF3DF8EDFE62217062680BB2F3EDF2F185074FE0220350DB29001C710F0450DAF466C5D819DC6D6A3340602DE9B6CB7DA8E17C90F798114FE9337B0574213FA5BCC0A319DBB4A7AC0CCA894E1F1",
|
||||
"12000322800000002400000004201B000000116840000000000F42407300770B6578616D706C652E636F6D811407C532442A675C881BA1235354D4AB9D023243A6F3E01073210287AAAB8FBE8C4C4A47F6F1228C6E5123A7ED844BFE88A9B22C2F7CC34279EEAA74473045022100B09DDF23144595B5A9523B20E605E138DC6549F5CA7B5984D7C32B0E3469DF6B022018845CA6C203D4B6288C87DDA439134C83E7ADF8358BD41A8A9141A9B631419F8114517D9B9609229E0CDFE2428B586738C5B2E84D45E1F1" ]
|
||||
11
test/fixtures/requests/index.js
vendored
11
test/fixtures/requests/index.js
vendored
@@ -20,7 +20,10 @@ module.exports = {
|
||||
allOptions: require('./prepare-payment-all-options'),
|
||||
noCounterparty: require('./prepare-payment-no-counterparty')
|
||||
},
|
||||
prepareSettings: require('./prepare-settings'),
|
||||
prepareSettings: {
|
||||
domain: require('./prepare-settings'),
|
||||
signers: require('./prepare-settings-signers')
|
||||
},
|
||||
prepareSuspendedPaymentCreation: {
|
||||
normal: require('./prepare-suspended-payment-creation'),
|
||||
full: require('./prepare-suspended-payment-creation-full')
|
||||
@@ -40,7 +43,8 @@ module.exports = {
|
||||
},
|
||||
sign: {
|
||||
normal: require('./sign'),
|
||||
suspended: require('./sign-suspended.json')
|
||||
suspended: require('./sign-suspended.json'),
|
||||
signAs: require('./sign-as')
|
||||
},
|
||||
getPaths: {
|
||||
normal: require('./getpaths/normal'),
|
||||
@@ -61,5 +65,8 @@ module.exports = {
|
||||
computeLedgerHash: {
|
||||
header: require('./compute-ledger-hash'),
|
||||
transactions: require('./compute-ledger-hash-transactions')
|
||||
},
|
||||
combine: {
|
||||
setDomain: require('./combine.json')
|
||||
}
|
||||
};
|
||||
|
||||
19
test/fixtures/requests/prepare-settings-signers.json
vendored
Normal file
19
test/fixtures/requests/prepare-settings-signers.json
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"signers": {
|
||||
"threshold": 2,
|
||||
"weights": [
|
||||
{
|
||||
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"weight": 1
|
||||
},
|
||||
{
|
||||
"address": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
|
||||
"weight": 1
|
||||
},
|
||||
{
|
||||
"address": "rwBYyfufTzk77zUSKEu4MvixfarC35av1J",
|
||||
"weight": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
8
test/fixtures/requests/sign-as.json
vendored
Normal file
8
test/fixtures/requests/sign-as.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"Account": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
|
||||
"Amount": "1000000000",
|
||||
"Destination": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||
"Fee": "50",
|
||||
"Sequence": 2,
|
||||
"TransactionType": "Payment"
|
||||
}
|
||||
4
test/fixtures/responses/combine.json
vendored
Normal file
4
test/fixtures/responses/combine.json
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"signedTransaction": "12000322800000002400000004201B000000116840000000000F42407300770B6578616D706C652E636F6D811407C532442A675C881BA1235354D4AB9D023243A6F3E01073210287AAAB8FBE8C4C4A47F6F1228C6E5123A7ED844BFE88A9B22C2F7CC34279EEAA74473045022100B09DDF23144595B5A9523B20E605E138DC6549F5CA7B5984D7C32B0E3469DF6B022018845CA6C203D4B6288C87DDA439134C83E7ADF8358BD41A8A9141A9B631419F8114517D9B9609229E0CDFE2428B586738C5B2E84D45E1E0107321026C784C1987F83BACBF02CD3E484AFC84ADE5CA6B36ED4DCA06D5BA233B9D382774473045022100E484F54FF909469FA2033E22EFF3DF8EDFE62217062680BB2F3EDF2F185074FE0220350DB29001C710F0450DAF466C5D819DC6D6A3340602DE9B6CB7DA8E17C90F798114FE9337B0574213FA5BCC0A319DBB4A7AC0CCA894E1F1",
|
||||
"id": "8A3BFD2214B4C8271ED62648FCE9ADE4EE82EF01827CF7D1F7ED497549A368CC"
|
||||
}
|
||||
9
test/fixtures/responses/index.js
vendored
9
test/fixtures/responses/index.js
vendored
@@ -87,7 +87,8 @@ module.exports = {
|
||||
fieldClear: require('./prepare-settings-field-clear.json'),
|
||||
noInstructions: require('./prepare-settings-no-instructions.json'),
|
||||
signed: require('./prepare-settings-signed.json'),
|
||||
noMaxLedgerVersion: require('./prepare-settings-no-maxledgerversion.json')
|
||||
noMaxLedgerVersion: require('./prepare-settings-no-maxledgerversion.json'),
|
||||
signers: require('./prepare-settings-signers.json')
|
||||
},
|
||||
prepareSuspendedPaymentCreation: {
|
||||
normal: require('./prepare-suspended-payment-creation'),
|
||||
@@ -108,7 +109,11 @@ module.exports = {
|
||||
},
|
||||
sign: {
|
||||
normal: require('./sign.json'),
|
||||
suspended: require('./sign-suspended.json')
|
||||
suspended: require('./sign-suspended.json'),
|
||||
signAs: require('./sign-as')
|
||||
},
|
||||
combine: {
|
||||
single: require('./combine.json')
|
||||
},
|
||||
submit: require('./submit.json'),
|
||||
ledgerEvent: require('./ledger-event.json')
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
{
|
||||
"signedTransaction": "12000322800000002400000017201B0086955368400000000000000C732102F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D87446304402202FBF6A6F74DFDA17C7341D532B66141206BC71A147C08DBDA6A950AA9A1741DC022055859A39F2486A46487F8DA261E3D80B4FDD26178A716A929F26377D1BEC7E43770A726970706C652E636F6D81145E7B112523F68D2F5E879DB4EAC51C6698A69304F9EA7C04746573747D0B74657874656420646174617E0A706C61696E2F74657874E1F1",
|
||||
"id": "4755D26FAC39E3E477870D4E03CC6783DDDF967FFBE240606755D3D03702FC16"
|
||||
}
|
||||
}
|
||||
|
||||
8
test/fixtures/responses/prepare-settings-signers.json
vendored
Normal file
8
test/fixtures/responses/prepare-settings-signers.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"txJSON": "{\"TransactionType\":\"SignerListSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"SignerQuorum\":2,\"SignerEntries\":[{\"SignerEntry\":{\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"SignerWeight\":1}},{\"SignerEntry\":{\"Account\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"SignerWeight\":1}},{\"SignerEntry\":{\"Account\":\"rwBYyfufTzk77zUSKEu4MvixfarC35av1J\",\"SignerWeight\":1}}],\"Flags\":2147483648,\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
|
||||
"instructions": {
|
||||
"fee": "0.000012",
|
||||
"sequence": 23,
|
||||
"maxLedgerVersion": 8820051
|
||||
}
|
||||
}
|
||||
4
test/fixtures/responses/sign-as.json
vendored
Normal file
4
test/fixtures/responses/sign-as.json
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"signedTransaction": "120000240000000261400000003B9ACA00684000000000000032730081142E244E6F20104E57C0C60BD823CB312BF10928C78314B5F762798A53D543A014CAF8B297CFF8F2F937E8F3E01073210330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD02074473045022100BB6FC77F26BC88587204CAA79B2230C420D7EC937B8AC3A0CF9B0BE988BAB0D002203BF86893BA3B764375FFFAD9D54A4AAEDABD07C4D72ADB9C1B20C10B4DD712898114B5F762798A53D543A014CAF8B297CFF8F2F937E8E1F1",
|
||||
"id": "AB7632D7C07E591658635CED6A5DDE832B22CA066907CB131DEFAAA925B98185"
|
||||
}
|
||||
@@ -110,7 +110,7 @@ describe('http server integration tests', function() {
|
||||
'prepareSettings',
|
||||
[
|
||||
{address},
|
||||
{settings: apiRequests.prepareSettings},
|
||||
{settings: apiRequests.prepareSettings.domain},
|
||||
{instructions: {
|
||||
maxFee: '0.000012',
|
||||
sequence: 23,
|
||||
|
||||
@@ -14,36 +14,45 @@ const {isValidSecret} = require('../../src/common');
|
||||
const TIMEOUT = 30000; // how long before each test case times out
|
||||
const INTERVAL = 1000; // how long to wait between checks for validated ledger
|
||||
|
||||
function acceptLedger(api) {
|
||||
return api.connection.request({command: 'ledger_accept'});
|
||||
}
|
||||
|
||||
function verifyTransaction(testcase, hash, type, options, txData) {
|
||||
function verifyTransaction(testcase, hash, type, options, txData, address) {
|
||||
console.log('VERIFY...');
|
||||
return testcase.api.getTransaction(hash, options).then(data => {
|
||||
assert(data && data.outcome);
|
||||
assert.strictEqual(data.type, type);
|
||||
assert.strictEqual(data.address, wallet.getAddress());
|
||||
assert.strictEqual(data.address, address);
|
||||
assert.strictEqual(data.outcome.result, 'tesSUCCESS');
|
||||
testcase.transactions.push(hash);
|
||||
if (testcase.transactions !== undefined) {
|
||||
testcase.transactions.push(hash);
|
||||
}
|
||||
return {txJSON: JSON.stringify(txData), id: hash, tx: data};
|
||||
}).catch(error => {
|
||||
if (error instanceof errors.PendingLedgerVersionError) {
|
||||
console.log('NOT VALIDATED YET...');
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => verifyTransaction(testcase, hash, type,
|
||||
options, txData).then(resolve, reject), INTERVAL);
|
||||
options, txData, address).then(resolve, reject), INTERVAL);
|
||||
});
|
||||
}
|
||||
console.log(error.stack);
|
||||
assert(false, 'Transaction not successful: ' + error.message);
|
||||
});
|
||||
}
|
||||
|
||||
function testTransaction(testcase, type, lastClosedLedgerVersion, prepared) {
|
||||
function testTransaction(testcase, type, lastClosedLedgerVersion, prepared,
|
||||
address = wallet.getAddress(), secret = wallet.getSecret()) {
|
||||
const txJSON = prepared.txJSON;
|
||||
assert(txJSON, 'missing txJSON');
|
||||
const txData = JSON.parse(txJSON);
|
||||
assert.strictEqual(txData.Account, wallet.getAddress());
|
||||
const signedData = testcase.api.sign(txJSON, wallet.getSecret());
|
||||
assert.strictEqual(txData.Account, address);
|
||||
const signedData = testcase.api.sign(txJSON, secret);
|
||||
console.log('PREPARED...');
|
||||
return testcase.api.submit(signedData.signedTransaction).then(data => {
|
||||
return testcase.api.submit(signedData.signedTransaction)
|
||||
.then(data => testcase.test.title.indexOf('multisign') !== -1 ?
|
||||
acceptLedger(testcase.api).then(() => data) : data).then(data => {
|
||||
console.log('SUBMITTED...');
|
||||
assert.strictEqual(data.resultCode, 'tesSUCCESS');
|
||||
const options = {
|
||||
@@ -52,13 +61,13 @@ function testTransaction(testcase, type, lastClosedLedgerVersion, prepared) {
|
||||
};
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => verifyTransaction(testcase, signedData.id, type,
|
||||
options, txData).then(resolve, reject), INTERVAL);
|
||||
options, txData, address).then(resolve, reject), INTERVAL);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function setup() {
|
||||
this.api = new RippleAPI({server: 'wss://s1.ripple.com'});
|
||||
function setup(server = 'wss://s1.ripple.com') {
|
||||
this.api = new RippleAPI({server});
|
||||
console.log('CONNECTING...');
|
||||
return this.api.connect().then(() => {
|
||||
console.log('CONNECTED...');
|
||||
@@ -91,7 +100,7 @@ describe('integration tests', function() {
|
||||
it('settings', function() {
|
||||
return this.api.getLedgerVersion().then(ledgerVersion => {
|
||||
return this.api.prepareSettings(address,
|
||||
requests.prepareSettings, instructions).then(prepared =>
|
||||
requests.prepareSettings.domain, instructions).then(prepared =>
|
||||
testTransaction(this, 'settings', ledgerVersion, prepared));
|
||||
});
|
||||
});
|
||||
@@ -232,7 +241,7 @@ describe('integration tests', function() {
|
||||
it('getSettings', function() {
|
||||
return this.api.getSettings(address).then(data => {
|
||||
assert(data);
|
||||
assert.strictEqual(data.domain, requests.prepareSettings.domain);
|
||||
assert.strictEqual(data.domain, requests.prepareSettings.domain.domain);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -313,3 +322,80 @@ describe('integration tests', function() {
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
function createAccount(api, address) {
|
||||
const root = 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh';
|
||||
const secret = 'snoPBrXtMeMyMHUVTgbuqAfg1SUTb';
|
||||
const amount = {
|
||||
currency: 'XRP',
|
||||
value: '10000'
|
||||
};
|
||||
return api.preparePayment(root, {
|
||||
source: {address: root, maxAmount: amount},
|
||||
destination: {address, amount}
|
||||
}).then(prepared => {
|
||||
return api.submit(api.sign(prepared.txJSON, secret).signedTransaction);
|
||||
}).then(() => {
|
||||
return acceptLedger(api);
|
||||
});
|
||||
}
|
||||
|
||||
describe.skip('integration tests - standalone rippled', function() {
|
||||
const instructions = {maxLedgerVersionOffset: 10, fee: '1'};
|
||||
this.timeout(TIMEOUT);
|
||||
|
||||
const url = 'ws://127.0.0.1:6006';
|
||||
// const url = 'wss://s.altnet.rippletest.net:51233';
|
||||
beforeEach(_.partial(setup, url));
|
||||
afterEach(teardown);
|
||||
const address = 'r5nx8ZkwEbFztnc8Qyi22DE9JYjRzNmvs';
|
||||
const secret = 'ss6F8381Br6wwpy9p582H8sBt19J3';
|
||||
const signer1address = 'rQDhz2ZNXmhxzCYwxU6qAbdxsHA4HV45Y2';
|
||||
const signer1secret = 'shK6YXzwYfnFVn3YZSaMh5zuAddKx';
|
||||
const signer2address = 'r3RtUvGw9nMoJ5FuHxuoVJvcENhKtuF9ud';
|
||||
const signer2secret = 'shUHQnL4EH27V4EiBrj6EfhWvZngF';
|
||||
|
||||
it('submit multisigned transaction', function() {
|
||||
const signers = {
|
||||
threshold: 2,
|
||||
weights: [
|
||||
{address: signer1address, weight: 1},
|
||||
{address: signer2address, weight: 1}
|
||||
]
|
||||
};
|
||||
let minLedgerVersion = null;
|
||||
return createAccount(this.api, address).then(() => {
|
||||
return this.api.getLedgerVersion().then(ledgerVersion => {
|
||||
minLedgerVersion = ledgerVersion;
|
||||
return this.api.prepareSettings(address, {signers}, instructions)
|
||||
.then(prepared => {
|
||||
return testTransaction(this, 'settings', ledgerVersion, prepared,
|
||||
address, secret);
|
||||
});
|
||||
});
|
||||
}).then(() => {
|
||||
return this.api.prepareSettings(
|
||||
address, {domain: 'example.com'}, instructions)
|
||||
.then(prepared => {
|
||||
const signed1 = this.api.sign(
|
||||
prepared.txJSON, signer1secret, {signAs: signer1address});
|
||||
const signed2 = this.api.sign(
|
||||
prepared.txJSON, signer2secret, {signAs: signer2address});
|
||||
const combined = this.api.combine([
|
||||
signed1.signedTransaction, signed2.signedTransaction
|
||||
]);
|
||||
return this.api.submit(combined.signedTransaction)
|
||||
.then(response => acceptLedger(this.api).then(() => response))
|
||||
.then(response => {
|
||||
assert.strictEqual(response.resultCode, 'tesSUCCESS');
|
||||
const options = {minLedgerVersion};
|
||||
return verifyTransaction(this, combined.id, 'settings',
|
||||
options, {}, address);
|
||||
}).catch(error => {
|
||||
console.log(error.message);
|
||||
throw error;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -249,6 +249,11 @@ module.exports = function(port) {
|
||||
}
|
||||
});
|
||||
|
||||
mock.on('request_submit_multisigned', function(request, conn) {
|
||||
assert.strictEqual(request.command, 'submit_multisigned');
|
||||
conn.send(createResponse(request, fixtures.submit.success));
|
||||
});
|
||||
|
||||
mock.on('request_account_lines', function(request, conn) {
|
||||
if (request.account === addresses.ACCOUNT) {
|
||||
conn.send(accountLinesResponse.normal(request));
|
||||
|
||||
Reference in New Issue
Block a user