Skip to content

Commit b94b18d

Browse files
committed
feat(algo): enhance transaction verification logic and add comprehensive unit tests
- Added verifyTransaction method with strict checks for Algorand transaction parameters and types - Implemented validation for payment, asset transfer, and key registration transactions
1 parent e75126e commit b94b18d

File tree

2 files changed

+421
-0
lines changed

2 files changed

+421
-0
lines changed

modules/sdk-coin-algo/src/algo.ts

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,122 @@ export class Algo extends BaseCoin {
580580
}
581581

582582
async verifyTransaction(params: VerifyTransactionOptions): Promise<boolean> {
583+
const { txParams, txPrebuild } = params;
584+
585+
if (!txParams) {
586+
throw new Error('missing txParams');
587+
}
588+
589+
if (!txPrebuild) {
590+
throw new Error('missing txPrebuild');
591+
}
592+
593+
if (!txPrebuild.txHex) {
594+
throw new Error('missing txHex in txPrebuild');
595+
}
596+
597+
const factory = this.getBuilder();
598+
const txBuilder = factory.from(txPrebuild.txHex);
599+
const tx = await txBuilder.build();
600+
const txJson = tx.toJson();
601+
602+
// Validate based on Algorand transaction type
603+
switch (txJson.type) {
604+
case 'pay':
605+
return this.validatePayTransaction(txJson, txParams);
606+
case 'axfer':
607+
return this.validateAssetTransferTransaction(txJson, txParams);
608+
case 'keyreg':
609+
return this.validateKeyRegTransaction(txJson, txParams);
610+
default:
611+
// For other transaction types, perform basic validation
612+
this.validateBasicTransaction(txJson);
613+
return true;
614+
}
615+
}
616+
617+
/**
618+
* Validate basic transaction fields common to all transaction types
619+
*/
620+
private validateBasicTransaction(txJson: any): void {
621+
if (!txJson.from) {
622+
throw new Error('Invalid transaction: missing sender address');
623+
}
624+
625+
if (!txJson.fee || txJson.fee < 0) {
626+
throw new Error('Invalid transaction: invalid fee');
627+
}
628+
}
629+
630+
/**
631+
* Validate Payment (pay) transaction
632+
*/
633+
private validatePayTransaction(txJson: any, txParams: any): boolean {
634+
this.validateBasicTransaction(txJson);
635+
636+
if (!txJson.to) {
637+
throw new Error('Invalid transaction: missing recipient address');
638+
}
639+
640+
if (txJson.amount === undefined || txJson.amount < 0) {
641+
throw new Error('Invalid transaction: invalid amount');
642+
}
643+
644+
// Validate recipients if provided in txParams
645+
if (txParams.recipients && txParams.recipients.length > 0) {
646+
if (txParams.recipients.length !== 1) {
647+
throw new Error('Algorand transactions can only have one recipient');
648+
}
649+
650+
const expectedRecipient = txParams.recipients[0];
651+
const expectedAmount = expectedRecipient.amount.toString();
652+
const expectedAddress = expectedRecipient.address;
653+
const actualAmount = txJson.amount.toString();
654+
const actualAddress = txJson.to;
655+
656+
if (expectedAmount !== actualAmount) {
657+
throw new Error('transaction amount in txPrebuild does not match the value given by client');
658+
}
659+
660+
if (expectedAddress.toLowerCase() !== actualAddress.toLowerCase()) {
661+
throw new Error('destination address does not match with the recipient address');
662+
}
663+
}
664+
665+
return true;
666+
}
667+
668+
/**
669+
* Validate Asset Transfer (axfer) transaction
670+
*/
671+
private validateAssetTransferTransaction(txJson: any, txParams: any): boolean {
672+
this.validateBasicTransaction(txJson);
673+
674+
// Basic amount validation if present
675+
if (txJson.amount !== undefined && txJson.amount < 0) {
676+
throw new Error('Invalid asset transfer transaction: invalid amount');
677+
}
678+
679+
return true;
680+
}
681+
682+
/**
683+
* Validate Key Registration (keyreg) transaction
684+
*/
685+
private validateKeyRegTransaction(txJson: any, txParams: any): boolean {
686+
this.validateBasicTransaction(txJson);
687+
688+
// Validate key registration specific fields
689+
if (txJson.voteFirst !== undefined && txJson.voteLast !== undefined) {
690+
if (txJson.voteFirst >= txJson.voteLast) {
691+
throw new Error('Invalid key registration: voteFirst must be less than voteLast');
692+
}
693+
}
694+
695+
if (txJson.voteKeyDilution !== undefined && txJson.voteKeyDilution <= 0) {
696+
throw new Error('Invalid key registration: voteKeyDilution must be positive');
697+
}
698+
583699
return true;
584700
}
585701

0 commit comments

Comments
 (0)