Skip to content
Open
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
6 changes: 3 additions & 3 deletions src/fee_bump_transaction.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export class FeeBumpTransaction extends TransactionBase {
const innerTxEnvelope = xdr.TransactionEnvelope.envelopeTypeTx(
tx.innerTx().v1()
);
this._feeSource = encodeMuxedAccountToAddress(this.tx.feeSource());
this._feeSource = encodeMuxedAccountToAddress(this._tx.feeSource());
this._innerTransaction = new Transaction(
innerTxEnvelope,
networkPassphrase
Expand Down Expand Up @@ -89,7 +89,7 @@ export class FeeBumpTransaction extends TransactionBase {
signatureBase() {
const taggedTransaction =
new xdr.TransactionSignaturePayloadTaggedTransaction.envelopeTypeTxFeeBump(
this.tx
this._tx
);

const txSignature = new xdr.TransactionSignaturePayload({
Expand All @@ -106,7 +106,7 @@ export class FeeBumpTransaction extends TransactionBase {
*/
toEnvelope() {
const envelope = new xdr.FeeBumpTransactionEnvelope({
tx: xdr.FeeBumpTransaction.fromXDR(this.tx.toXDR()), // make a copy of the tx
tx: xdr.FeeBumpTransaction.fromXDR(this._tx.toXDR()), // make a copy of the tx
signatures: this.signatures.slice() // make a copy of the signatures
});

Expand Down
27 changes: 7 additions & 20 deletions src/memo.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,33 +102,20 @@ export class Memo {
throw error;
}

// Reject anything that isn't plain decimal digits (no scientific notation,
// no decimals, no signs). BigNumber accepts formats like "1e18" and "1.0"
// which pass numeric checks but crash BigInt()/UnsignedHyper.fromString().
if (!/^\d+$/.test(value)) {
throw error;
}
Comment on lines +105 to +110
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback


let number;
try {
number = new BigNumber(value);
} catch (e) {
throw error;
}

// Infinity
if (!number.isFinite()) {
throw error;
}

// NaN
if (number.isNaN()) {
throw error;
}

// Negative
if (number.isNegative()) {
throw error;
}

// Decimal
if (!number.isInteger()) {
throw error;
}

// Exceeds uint64 max (2^64 - 1)
if (number.isGreaterThan('18446744073709551615')) {
throw error;
Expand Down
8 changes: 4 additions & 4 deletions src/transaction.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,11 @@ export class Transaction extends TransactionBase {
switch (this._envelopeType) {
case xdr.EnvelopeType.envelopeTypeTxV0():
this._source = StrKey.encodeEd25519PublicKey(
this.tx.sourceAccountEd25519()
this._tx.sourceAccountEd25519()
);
break;
default:
this._source = encodeMuxedAccountToAddress(this.tx.sourceAccount());
this._source = encodeMuxedAccountToAddress(this._tx.sourceAccount());
break;
}

Expand Down Expand Up @@ -256,7 +256,7 @@ export class Transaction extends TransactionBase {
* @returns {Buffer}
*/
signatureBase() {
let tx = this.tx;
let tx = this._tx;

// Backwards Compatibility: Use ENVELOPE_TYPE_TX to sign ENVELOPE_TYPE_TX_V0
// we need a Transaction to generate the signature base
Expand Down Expand Up @@ -288,7 +288,7 @@ export class Transaction extends TransactionBase {
* @returns {xdr.TransactionEnvelope}
*/
toEnvelope() {
const rawTx = this.tx.toXDR();
const rawTx = this._tx.toXDR();
const signatures = this.signatures.slice(); // make a copy of the signatures

let envelope;
Expand Down
6 changes: 5 additions & 1 deletion src/transaction_base.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@ export class TransactionBase {
}

get tx() {
return this._tx;
// Return a defensive copy to prevent mutation of the internal XDR object
// after construction. Signing and serialization use this._tx directly,
// so exposing the live reference could let callers alter signed bytes
// without changing the cached display fields (fee, source, memo, etc.).
return this._tx.constructor.fromXDR(this._tx.toXDR());
}
Comment on lines 34 to 40
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback


set tx(value) {
Expand Down
4 changes: 4 additions & 0 deletions test/unit/memo_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ describe('Memo.id()', function () {
expect(() => StellarBase.Memo.id('-1')).to.throw(/Expects a uint64/);
// decimal
expect(() => StellarBase.Memo.id('1.5')).to.throw(/Expects a uint64/);
// trailing decimal zero (BigNumber accepts but must be rejected)
expect(() => StellarBase.Memo.id('1.0')).to.throw(/Expects a uint64/);
// scientific notation (BigNumber accepts but BigInt()/UnsignedHyper crashes)
expect(() => StellarBase.Memo.id('1e18')).to.throw(/Expects a uint64/);
// overflow: 2^64 silently became 0 before this fix
expect(() => StellarBase.Memo.id('18446744073709551616')).to.throw(
/Expects a uint64/
Expand Down
7 changes: 7 additions & 0 deletions test/unit/transaction_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ describe('Transaction', function () {
const envelope = transaction.toEnvelope().value();
envelope.tx().fee(StellarBase.xdr.Int64.fromString('300'));

expect(transaction.tx.fee().toString()).to.equal('100');
});
it('tx getter returns a defensive copy that does not affect internal XDR', function () {
const transaction = this.transaction;
const txCopy = transaction.tx;
txCopy.fee(StellarBase.xdr.Int64.fromString('999'));

expect(transaction.tx.fee().toString()).to.equal('100');
});
});
Expand Down
Loading