Skip to content

Commit 81f5397

Browse files
feat: transaction signWith method broken into smaller methods (#788)
1 parent cd0f4db commit 81f5397

File tree

2 files changed

+60
-9
lines changed

2 files changed

+60
-9
lines changed

src/model/transaction/Transaction.ts

+35-9
Original file line numberDiff line numberDiff line change
@@ -214,16 +214,12 @@ export abstract class Transaction {
214214
public signWith(account: Account, generationHash: string): SignedTransaction {
215215
const generationHashBytes = Array.from(Convert.hexToUint8(generationHash));
216216
const byteBuffer = Array.from(this.generateBytes());
217+
// 1. prepare the raw transaction to be signed
217218
const signingBytes = this.getSigningBytes(byteBuffer, generationHashBytes);
218-
const keyPairEncoded = KeyPair.createKeyPairFromPrivateKeyString(account.privateKey);
219-
const signature = Array.from(KeyPair.sign(keyPairEncoded, new Uint8Array(signingBytes)));
220-
const signedTransactionBuffer = byteBuffer
221-
.splice(0, 8)
222-
.concat(signature)
223-
.concat(Array.from(keyPairEncoded.publicKey))
224-
.concat(Array.from(new Uint8Array(4)))
225-
.concat(byteBuffer.splice(64 + 32 + 4, byteBuffer.length));
226-
const payload = Convert.uint8ToHex(signedTransactionBuffer);
219+
// 2. sign the raw transaction
220+
const signature = Transaction.signRawTransaction(account.privateKey, Uint8Array.from(signingBytes));
221+
// 3. prepare the (signed) payload
222+
const payload = Transaction.preparePayload(Uint8Array.from(byteBuffer), signature, account.publicKey);
227223
return new SignedTransaction(
228224
payload,
229225
Transaction.createTransactionHash(payload, generationHashBytes),
@@ -233,6 +229,36 @@ export abstract class Transaction {
233229
);
234230
}
235231

232+
/**
233+
* Signs raw transaction with the given private key
234+
* @param {string} privateKey - Private key of the signer account
235+
* @param {Uint8Array} rawTransactionSigningBytes - Raw transaction siging bytes
236+
* @returns {Uint8Array} Signature byte array
237+
*/
238+
public static signRawTransaction(privateKey: string, rawTransactionSigningBytes: Uint8Array): Uint8Array {
239+
const keyPairEncoded = KeyPair.createKeyPairFromPrivateKeyString(privateKey);
240+
return KeyPair.sign(keyPairEncoded, new Uint8Array(rawTransactionSigningBytes));
241+
}
242+
243+
/**
244+
* Prepares and return signed payload
245+
* @param {Uint8Array} serializedTransaction Serialized transaction
246+
* @param {Uint8Array} signature Signature of the transaction
247+
* @param {string} publicKey Public key of the signing account
248+
* @returns {string} Payload (ready to be announced)
249+
*/
250+
public static preparePayload(serializedTransaction: Uint8Array, signature: Uint8Array, publicKey: string): string {
251+
const transactionBytes = Array.from(serializedTransaction);
252+
const signatureBytes = Array.from(signature);
253+
const signedTransactionBuffer = transactionBytes
254+
.splice(0, 8)
255+
.concat(signatureBytes)
256+
.concat(Array.from(Convert.hexToUint8(publicKey)))
257+
.concat(Array.from(new Uint8Array(4)))
258+
.concat(transactionBytes.splice(64 + 32 + 4, transactionBytes.length));
259+
return Convert.uint8ToHex(signedTransactionBuffer);
260+
}
261+
236262
/**
237263
* Generate signing bytes
238264
* @param payloadBytes Payload buffer

test/model/transaction/Transaction.spec.ts

+25
Original file line numberDiff line numberDiff line change
@@ -391,4 +391,29 @@ describe('Transaction', () => {
391391
expect((tx as Transaction).isSigned(account.address)).to.be.true;
392392
expect((tx as Transaction).isSigned(Address.createFromRawAddress('VATNE7Q5BITMUTRRN6IB4I7FLSDRDWZA35C4KNQ'))).to.be.false;
393393
});
394+
395+
it('should prepare valid transaction payload', () => {
396+
const tx = TransferTransaction.create(
397+
Deadline.createFromDTO('1'),
398+
Address.createFromRawAddress('VATNE7Q5BITMUTRRN6IB4I7FLSDRDWZA35C4KNQ'),
399+
[],
400+
PlainMessage.create('test-message'),
401+
NetworkType.PRIVATE_TEST,
402+
) as Transaction;
403+
const expectedPayload =
404+
'AD00000000000000F5CEC2900A317ED93F5BC6621AE11FF960E07BD9D780CF625EA49FD8F073973EB4DF2598B089CC78A6C48519138EB1CC0A0927467D1925838DDA074C6C81170F9801508C58666C746F471538E43002B85B1CD542F9874B2861183919BA8787B60000000001A8544100000000000000000100000000000000A826D27E1D0A26CA4E316F901E23E55C8711DB20DF45C5360D0000000000000000746573742D6D657373616765';
405+
const signature =
406+
'F5CEC2900A317ED93F5BC6621AE11FF960E07BD9D780CF625EA49FD8F073973EB4DF2598B089CC78A6C48519138EB1CC0A0927467D1925838DDA074C6C81170F';
407+
const payload = Transaction.preparePayload(Convert.hexToUint8(tx.serialize()), Convert.hexToUint8(signature), account.publicKey);
408+
expect(payload).to.be.eq(expectedPayload);
409+
});
410+
411+
it('should sign raw transaction and produce a valid signature', () => {
412+
const txSigningBytes =
413+
'57F7DA205008026C776CB6AED843393F04CD458E0AA2D9F1D5F31A402072B2D601A8544100000000000000000100000000000000A826D27E1D0A26CA4E316F901E23E55C8711DB20DF45C5360D0000000000000000746573742D6D657373616765';
414+
const expectedSignature =
415+
'F5CEC2900A317ED93F5BC6621AE11FF960E07BD9D780CF625EA49FD8F073973EB4DF2598B089CC78A6C48519138EB1CC0A0927467D1925838DDA074C6C81170F';
416+
const signature = Transaction.signRawTransaction(account.privateKey, Convert.hexToUint8(txSigningBytes));
417+
expect(Convert.uint8ToHex(signature)).to.be.eq(expectedSignature);
418+
});
394419
});

0 commit comments

Comments
 (0)