-
Notifications
You must be signed in to change notification settings - Fork 300
feat(algo): add verify transaction function #7277
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
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,291 @@ | ||
| import { Talgo } from '../../src'; | ||
| import { TestBitGo, TestBitGoAPI } from '@bitgo/sdk-test'; | ||
| import { BitGoAPI } from '@bitgo/sdk-api'; | ||
| import * as testData from '../fixtures/resources'; | ||
| import assert from 'assert'; | ||
|
|
||
| describe('Algorand Verify Transaction:', function () { | ||
| let bitgo: TestBitGoAPI; | ||
| let basecoin: Talgo; | ||
|
|
||
| before(function () { | ||
| bitgo = TestBitGo.decorate(BitGoAPI, { env: 'mock' }); | ||
| bitgo.safeRegister('talgo', Talgo.createInstance); | ||
| bitgo.initializeTestVars(); | ||
| basecoin = bitgo.coin('talgo') as Talgo; | ||
| }); | ||
|
|
||
| describe('Parameter Validation', () => { | ||
| it('should throw error when txParams is missing', async function () { | ||
| const txPrebuild = { | ||
| txHex: testData.rawTx.transfer.unsigned, | ||
| }; | ||
|
|
||
| await assert.rejects( | ||
| basecoin.verifyTransaction({ | ||
| txPrebuild, | ||
| wallet: {} as any, | ||
| txParams: undefined as any, | ||
| }), | ||
| { | ||
| message: 'missing txParams', | ||
| } | ||
| ); | ||
| }); | ||
|
|
||
| it('should throw error when txPrebuild is missing', async function () { | ||
| const txParams = { | ||
| recipients: [{ address: testData.accounts.account2.address, amount: '10000' }], | ||
| }; | ||
|
|
||
| await assert.rejects( | ||
| basecoin.verifyTransaction({ | ||
| txParams, | ||
| wallet: {} as any, | ||
| txPrebuild: undefined as any, | ||
| }), | ||
| { | ||
| message: 'missing txPrebuild', | ||
| } | ||
| ); | ||
| }); | ||
|
|
||
| it('should throw error when txPrebuild.txHex is missing', async function () { | ||
| const txParams = { | ||
| recipients: [{ address: testData.accounts.account2.address, amount: '10000' }], | ||
| }; | ||
| const txPrebuild = {}; | ||
|
|
||
| await assert.rejects(basecoin.verifyTransaction({ txParams, txPrebuild, wallet: {} as any }), { | ||
| message: 'missing txHex in txPrebuild', | ||
| }); | ||
| }); | ||
| }); | ||
|
|
||
| describe('Payment Transaction Validation', () => { | ||
| it('should validate valid payment transaction', async function () { | ||
| const txParams = { | ||
| recipients: [ | ||
| { | ||
| address: testData.accounts.account2.address, | ||
| amount: '10000', | ||
| }, | ||
| ], | ||
| }; | ||
| const txPrebuild = { | ||
| txHex: testData.rawTx.transfer.unsigned, | ||
| }; | ||
|
|
||
| const result = await basecoin.verifyTransaction({ txParams, txPrebuild, wallet: {} as any }); | ||
| assert.strictEqual(result, true); | ||
| }); | ||
|
|
||
| it('should fail with amount mismatch', async function () { | ||
| const txParams = { | ||
| recipients: [ | ||
| { | ||
| address: testData.accounts.account2.address, | ||
| amount: '20000', // Different amount than in the transaction | ||
| }, | ||
| ], | ||
| }; | ||
| const txPrebuild = { | ||
| txHex: testData.rawTx.transfer.unsigned, | ||
| }; | ||
|
|
||
| await assert.rejects(basecoin.verifyTransaction({ txParams, txPrebuild, wallet: {} as any }), { | ||
| message: 'transaction amount in txPrebuild does not match the value given by client', | ||
| }); | ||
| }); | ||
|
|
||
| it('should fail with address mismatch', async function () { | ||
| const txParams = { | ||
| recipients: [ | ||
| { | ||
| address: testData.accounts.account3.address, // Different address than in transaction | ||
| amount: '10000', | ||
| }, | ||
| ], | ||
| }; | ||
| const txPrebuild = { | ||
| txHex: testData.rawTx.transfer.unsigned, | ||
| }; | ||
|
|
||
| await assert.rejects(basecoin.verifyTransaction({ txParams, txPrebuild, wallet: {} as any }), { | ||
| message: 'destination address does not match with the recipient address', | ||
| }); | ||
| }); | ||
|
|
||
| it('should fail with multiple recipients', async function () { | ||
| const txParams = { | ||
| recipients: [ | ||
| { | ||
| address: testData.accounts.account2.address, | ||
| amount: '5000', | ||
| }, | ||
| { | ||
| address: testData.accounts.account3.address, | ||
| amount: '5000', | ||
| }, | ||
| ], | ||
| }; | ||
| const txPrebuild = { | ||
| txHex: testData.rawTx.transfer.unsigned, | ||
| }; | ||
|
|
||
| await assert.rejects(basecoin.verifyTransaction({ txParams, txPrebuild, wallet: {} as any }), { | ||
| message: 'Algorand transactions can only have one recipient', | ||
| }); | ||
| }); | ||
|
|
||
| it('should validate transaction without recipients in txParams', async function () { | ||
| const txParams = { | ||
| // No recipients specified | ||
| }; | ||
| const txPrebuild = { | ||
| txHex: testData.rawTx.transfer.unsigned, | ||
| }; | ||
|
|
||
| const result = await basecoin.verifyTransaction({ txParams, txPrebuild, wallet: {} as any }); | ||
| assert.strictEqual(result, true); | ||
| }); | ||
| }); | ||
|
|
||
| describe('Asset Transfer Transaction Validation', () => { | ||
| it('should validate valid asset transfer transaction', async function () { | ||
| const txParams = { | ||
| recipients: [ | ||
| { | ||
| address: testData.accounts.account2.address, | ||
| amount: '1000', | ||
| }, | ||
| ], | ||
| }; | ||
| const txPrebuild = { | ||
| txHex: testData.rawTx.assetTransfer.unsigned, | ||
| }; | ||
|
|
||
| const result = await basecoin.verifyTransaction({ txParams, txPrebuild, wallet: {} as any }); | ||
| assert.strictEqual(result, true); | ||
| }); | ||
|
|
||
| it('should validate token enable transaction', async function () { | ||
| const txParams = { | ||
| type: 'enabletoken', | ||
| recipients: [ | ||
| { | ||
| address: testData.accounts.account1.address, | ||
| amount: '0', | ||
| }, | ||
| ], | ||
| }; | ||
| const txPrebuild = { | ||
| // Using existing asset transfer for test - in real scenario this would be an opt-in transaction | ||
| txHex: testData.rawTx.assetTransfer.unsigned, | ||
| }; | ||
|
|
||
| const result = await basecoin.verifyTransaction({ txParams, txPrebuild, wallet: {} as any }); | ||
| assert.strictEqual(result, true); | ||
| }); | ||
| }); | ||
|
|
||
| describe('Transaction Structure Validation', () => { | ||
| it('should handle malformed transaction hex gracefully', async function () { | ||
| const txParams = { | ||
| recipients: [{ address: testData.accounts.account2.address, amount: '10000' }], | ||
| }; | ||
| const txPrebuild = { | ||
| txHex: 'invalid_hex_data', | ||
| }; | ||
|
|
||
| await assert.rejects(basecoin.verifyTransaction({ txParams, txPrebuild, wallet: {} as any })); | ||
| }); | ||
|
|
||
| it('should validate transaction with memo', async function () { | ||
| const txParams = { | ||
| recipients: [ | ||
| { | ||
| address: testData.accounts.account2.address, | ||
| amount: '10000', | ||
| }, | ||
| ], | ||
| }; | ||
| const txPrebuild = { | ||
| txHex: testData.rawTx.transfer.unsigned, // This transaction includes a memo | ||
| }; | ||
|
|
||
| const result = await basecoin.verifyTransaction({ txParams, txPrebuild, wallet: {} as any }); | ||
| assert.strictEqual(result, true); | ||
| }); | ||
| }); | ||
|
|
||
| describe('Edge Cases', () => { | ||
| it('should handle zero amount transactions', async function () { | ||
| const txParams = { | ||
| recipients: [ | ||
| { | ||
| address: testData.accounts.account1.address, | ||
| amount: '0', | ||
| }, | ||
| ], | ||
| }; | ||
| const txPrebuild = { | ||
| // This would need to be a valid 0-amount transaction hex | ||
| txHex: testData.rawTx.transfer.unsigned, | ||
| }; | ||
|
|
||
| // Note: This might fail if the test data doesn't match the expected amount | ||
| // In a real scenario, we'd need proper test data for 0-amount transactions | ||
| try { | ||
| const result = await basecoin.verifyTransaction({ txParams, txPrebuild, wallet: {} as any }); | ||
| assert.strictEqual(result, true); | ||
| } catch (error) { | ||
| // Expected if amounts don't match | ||
| assert.ok(error.message.includes('amount')); | ||
| } | ||
| }); | ||
|
|
||
| it('should handle close remainder transactions', async function () { | ||
| const txParams = { | ||
| recipients: [ | ||
| { | ||
| address: testData.accounts.account3.address, | ||
| amount: '10000', | ||
| }, | ||
| ], | ||
| }; | ||
| const txPrebuild = { | ||
| txHex: testData.rawTx.transfer.unsigned, | ||
| }; | ||
|
|
||
| // This test validates that transactions with closeRemainderTo field are handled | ||
| try { | ||
| const result = await basecoin.verifyTransaction({ txParams, txPrebuild, wallet: {} as any }); | ||
| assert.strictEqual(result, true); | ||
| } catch (error) { | ||
| // Expected if addresses don't match | ||
| assert.ok(error.message.includes('address')); | ||
| } | ||
| }); | ||
| }); | ||
|
|
||
| describe('Network Validation', () => { | ||
| it('should validate transactions for different networks', async function () { | ||
| // Test that transactions work regardless of genesis hash/ID | ||
| const txParams = { | ||
| recipients: [ | ||
| { | ||
| address: testData.accounts.account2.address, | ||
| amount: '10000', | ||
| }, | ||
| ], | ||
| }; | ||
| const txPrebuild = { | ||
| txHex: testData.rawTx.transfer.unsigned, | ||
| }; | ||
|
|
||
| const result = await basecoin.verifyTransaction({ txParams, txPrebuild, wallet: {} as any }); | ||
| assert.strictEqual(result, true); | ||
| }); | ||
| }); | ||
| }); |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.