Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend StrKey to handle xdr.MuxedAccount #330

Merged
merged 4 commits into from
Apr 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/fee_bump_transaction.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export class FeeBumpTransaction extends TransactionBase {
const innerTxEnvelope = xdr.TransactionEnvelope.envelopeTypeTx(
tx.innerTx().v1()
);

this._feeSource = StrKey.encodeMuxedAccount(this.tx.feeSource().toXDR());
this._innerTransaction = new Transaction(
innerTxEnvelope,
networkPassphrase
Expand All @@ -62,7 +62,7 @@ export class FeeBumpTransaction extends TransactionBase {
* @readonly
*/
get feeSource() {
return this._muxedToString(this.tx.feeSource());
return this._feeSource;
}

/**
Expand Down
33 changes: 28 additions & 5 deletions src/strkey.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import isUndefined from 'lodash/isUndefined';
import isNull from 'lodash/isNull';
import isString from 'lodash/isString';
import { verifyChecksum } from './util/checksum';
import xdr from './generated/stellar-xdr_generated';

const versionBytes = {
ed25519PublicKey: 6 << 3, // G
Expand Down Expand Up @@ -110,21 +111,43 @@ export class StrKey {
}

/**
* Encodes data to strkey muxed account.
* @param {Buffer} data data to encode
* Encodes data to strkey.
* @param {Buffer} data data to encode. It must represent a valid xdr.MuxedAccount
* @returns {string}
*/
static encodeMuxedAccount(data) {
return encodeCheck('muxedAccount', data);
const muxed = xdr.MuxedAccount.fromXDR(data);

if (muxed.switch() === xdr.CryptoKeyType.keyTypeEd25519()) {
return encodeCheck('ed25519PublicKey', muxed.ed25519());
}

return encodeCheck('muxedAccount', muxed.med25519().toXDR());
}

/**
* Decodes strkey muxed account to raw data.
* Decodes strkey muxed account to raw data. The raw data can be used to create a valid xdr.MuxedAccount
* @param {string} data data to decode
* @returns {Buffer}
*/
static decodeMuxedAccount(data) {
return decodeCheck('muxedAccount', data);
let muxed;
switch (data.length) {
case 56:
muxed = xdr.MuxedAccount.keyTypeEd25519(
decodeCheck('ed25519PublicKey', data)
);
break;
case 69:
muxed = xdr.MuxedAccount.keyTypeMuxedEd25519(
xdr.MuxedAccountMed25519.fromXDR(decodeCheck('muxedAccount', data))
);
break;
default:
throw new Error('invalid encoded string');
}

return muxed.toXDR();
}
}

Expand Down
27 changes: 14 additions & 13 deletions src/transaction.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,19 @@ export class Transaction extends TransactionBase {
this._memo = tx.memo();
this._sequence = tx.seqNum().toString();

switch (this._envelopeType) {
case xdr.EnvelopeType.envelopeTypeTxV0():
this._source = StrKey.encodeEd25519PublicKey(
this.tx.sourceAccountEd25519()
);
break;
default:
this._source = StrKey.encodeMuxedAccount(
this.tx.sourceAccount().toXDR()
);
break;
}

const timeBounds = tx.timeBounds();
if (timeBounds) {
this._timeBounds = {
Expand Down Expand Up @@ -91,19 +104,7 @@ export class Transaction extends TransactionBase {
* @readonly
*/
get source() {
const envelopeType = this._envelopeType;
let source;

switch (envelopeType) {
case xdr.EnvelopeType.envelopeTypeTxV0():
source = StrKey.encodeEd25519PublicKey(this.tx.sourceAccountEd25519());
break;
default:
source = this._muxedToString(this.tx.sourceAccount());
break;
}

return source;
return this._source;
}

set source(value) {
Expand Down
9 changes: 0 additions & 9 deletions src/transaction_base.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import xdr from './generated/stellar-xdr_generated';
import { hash } from './hashing';
import { Keypair } from './keypair';
import { StrKey } from './strkey';

/**
* @ignore
Expand Down Expand Up @@ -200,12 +199,4 @@ export class TransactionBase {
.toXDR()
.toString('base64');
}

_muxedToString(muxedAccount) {
if (muxedAccount.switch() === xdr.CryptoKeyType.keyTypeEd25519()) {
return StrKey.encodeEd25519PublicKey(muxedAccount.ed25519());
}

return StrKey.encodeMuxedAccount(muxedAccount.med25519().toXDR());
}
}
2 changes: 1 addition & 1 deletion test/unit/fee_bump_transation_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ describe('FeeBumpTransaction', function() {
this.networkPassphrase
);
expect(txWithMuxedAccount.feeSource).to.equal(
StellarBase.StrKey.encodeMuxedAccount(med25519.toXDR())
StellarBase.StrKey.encodeMuxedAccount(muxedAccount.toXDR())
);
});
});
Expand Down
43 changes: 39 additions & 4 deletions test/unit/strkey_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,21 +106,38 @@ describe('StrKey', function() {
});

describe('muxed account', function() {
it('decodes correctly', function() {
it('decodes med25519 correctly', function() {
const med25519 = new StellarBase.xdr.MuxedAccountMed25519({
id: StellarBase.xdr.Uint64.fromString('0'),
ed25519: StellarBase.StrKey.decodeEd25519PublicKey(
'GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ'
)
});
let expectedBuffer = med25519.toXDR();
let expectedBuffer = StellarBase.xdr.MuxedAccount.keyTypeMuxedEd25519(
med25519
).toXDR();
let strkey =
'MAAAAAAAAAAAAAB7BQ2L7E5NBWMXDUCMZSIPOBKRDSBYVLMXGSSKF6YNPIB7Y77ITLVL6';
expect(StellarBase.StrKey.decodeMuxedAccount(strkey)).to.eql(
expectedBuffer
);
});

it('decodes ed25519 correctly', function() {
const rawEd25519 = StellarBase.StrKey.decodeEd25519PublicKey(
'GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ'
);
const expectedBuffer = StellarBase.xdr.MuxedAccount.keyTypeEd25519(
rawEd25519
).toXDR();
const strkey =
'GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ';

expect(StellarBase.StrKey.decodeMuxedAccount(strkey)).to.eql(
expectedBuffer
);
});

it('throws an error: unused trailing bit must be zero in the encoding of the last three bytes (24 bits) as five base-32 symbols (25 bits)', function() {
// unused trailing bit must be zero in the encoding of the last three bytes (24 bits) as five base-32 symbols (25 bits)
expect(() =>
Expand Down Expand Up @@ -214,20 +231,38 @@ describe('StrKey', function() {
});

describe('muxed account', function() {
it('encodes a buffer correctly', function() {
it('encodes med25519 accounts correctly', function() {
const med25519 = new StellarBase.xdr.MuxedAccountMed25519({
id: StellarBase.xdr.Uint64.fromString('0'),
ed25519: StellarBase.StrKey.decodeEd25519PublicKey(
'GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ'
)
});
let buffer = med25519.toXDR();
const buffer = StellarBase.xdr.MuxedAccount.keyTypeMuxedEd25519(
med25519
).toXDR();

let expectedMuxedAccount =
'MAAAAAAAAAAAAAB7BQ2L7E5NBWMXDUCMZSIPOBKRDSBYVLMXGSSKF6YNPIB7Y77ITLVL6';
expect(StellarBase.StrKey.encodeMuxedAccount(buffer)).to.eql(
expectedMuxedAccount
);
});
it('encodes ed25519 accounts correctly', function() {
const ed25519 = StellarBase.StrKey.decodeEd25519PublicKey(
'GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ'
);

const buffer = StellarBase.xdr.MuxedAccount.keyTypeEd25519(
ed25519
).toXDR();

let expectedMuxedAccount =
'GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ';
expect(StellarBase.StrKey.encodeMuxedAccount(buffer)).to.eql(
expectedMuxedAccount
);
});
});
});

Expand Down
2 changes: 1 addition & 1 deletion test/unit/transaction_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,7 @@ describe('Transaction', function() {
networkPassphrase
);
expect(txWithMuxedAccount.source).to.equal(
StellarBase.StrKey.encodeMuxedAccount(med25519.toXDR())
StellarBase.StrKey.encodeMuxedAccount(muxedAccount.toXDR())
);
expect(tx.source).to.equal(source.publicKey());
});
Expand Down