From a154696cbe1d527915fe4eebb61463e1164a059f Mon Sep 17 00:00:00 2001 From: Jason Paulos Date: Thu, 1 Apr 2021 15:36:09 -0400 Subject: [PATCH] Fix encoding of all 0 lease and assetMetadataHash --- src/transaction.ts | 26 +++++++---- tests/5.Transaction.js | 101 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+), 9 deletions(-) diff --git a/src/transaction.ts b/src/transaction.ts index 536d64fa2..513bcd8e2 100644 --- a/src/transaction.ts +++ b/src/transaction.ts @@ -371,20 +371,24 @@ export class Transaction implements TransactionStorageStructure { txn.assetMetadataHash.length !== 0 ) { if (typeof txn.assetMetadataHash === 'string') { - const encoded = Buffer.from(txn.assetMetadataHash); - if (encoded.byteLength !== ASSET_METADATA_HASH_LENGTH) { - throw Error( - `assetMetadataHash must be a ${ASSET_METADATA_HASH_LENGTH} byte Uint8Array or string.` - ); - } - txn.assetMetadataHash = new Uint8Array(encoded); - } else if ( + txn.assetMetadataHash = new Uint8Array( + Buffer.from(txn.assetMetadataHash) + ); + } + + if ( txn.assetMetadataHash.constructor !== Uint8Array || txn.assetMetadataHash.byteLength !== ASSET_METADATA_HASH_LENGTH - ) + ) { throw Error( `assetMetadataHash must be a ${ASSET_METADATA_HASH_LENGTH} byte Uint8Array or string.` ); + } + + if (txn.assetMetadataHash.every((value) => value === 0)) { + // if hash contains all 0s, omit it + txn.assetMetadataHash = undefined; + } } else { txn.assetMetadataHash = undefined; } @@ -401,6 +405,10 @@ export class Transaction implements TransactionStorageStructure { throw Error( `lease must be of length ${ALGORAND_TRANSACTION_LEASE_LENGTH.toString()}.` ); + if (txn.lease.every((value) => value === 0)) { + // if lease contains all 0s, omit it + txn.lease = new Uint8Array(0); + } } else { txn.lease = new Uint8Array(0); } diff --git a/tests/5.Transaction.js b/tests/5.Transaction.js index a4e93ac78..d34febe4c 100644 --- a/tests/5.Transaction.js +++ b/tests/5.Transaction.js @@ -145,6 +145,107 @@ describe('Sign', () => { ); }); + it('should not drop a note of all zeros', () => { + const txnWithNote = new algosdk.Transaction({ + from: '7ZUECA7HFLZTXENRV24SHLU4AVPUTMTTDUFUBNBD64C73F3UHRTHAIOF6Q', + to: '7ZUECA7HFLZTXENRV24SHLU4AVPUTMTTDUFUBNBD64C73F3UHRTHAIOF6Q', + fee: 10, + amount: 847, + firstRound: 51, + lastRound: 61, + genesisHash: 'JgsgCaCTqIaLeVhyL6XlRu3n7Rfk2FxMeK+wRSaQ7dI=', + note: new Uint8Array(32), + }); + + const txnWithoutNote = new algosdk.Transaction({ + from: '7ZUECA7HFLZTXENRV24SHLU4AVPUTMTTDUFUBNBD64C73F3UHRTHAIOF6Q', + to: '7ZUECA7HFLZTXENRV24SHLU4AVPUTMTTDUFUBNBD64C73F3UHRTHAIOF6Q', + fee: 10, + amount: 847, + firstRound: 51, + lastRound: 61, + genesisHash: 'JgsgCaCTqIaLeVhyL6XlRu3n7Rfk2FxMeK+wRSaQ7dI=', + }); + + const serializedWithNote = algosdk.encodeUnsignedTransaction(txnWithNote); + const serializedWithoutNote = algosdk.encodeUnsignedTransaction( + txnWithoutNote + ); + + assert.notDeepStrictEqual(serializedWithNote, serializedWithoutNote); + }); + + it('should drop a lease of all zeros', () => { + const txnWithLease = new algosdk.Transaction({ + from: '7ZUECA7HFLZTXENRV24SHLU4AVPUTMTTDUFUBNBD64C73F3UHRTHAIOF6Q', + to: '7ZUECA7HFLZTXENRV24SHLU4AVPUTMTTDUFUBNBD64C73F3UHRTHAIOF6Q', + fee: 10, + amount: 847, + firstRound: 51, + lastRound: 61, + genesisHash: 'JgsgCaCTqIaLeVhyL6XlRu3n7Rfk2FxMeK+wRSaQ7dI=', + lease: new Uint8Array(32), + }); + + const txnWithoutLease = new algosdk.Transaction({ + from: '7ZUECA7HFLZTXENRV24SHLU4AVPUTMTTDUFUBNBD64C73F3UHRTHAIOF6Q', + to: '7ZUECA7HFLZTXENRV24SHLU4AVPUTMTTDUFUBNBD64C73F3UHRTHAIOF6Q', + fee: 10, + amount: 847, + firstRound: 51, + lastRound: 61, + genesisHash: 'JgsgCaCTqIaLeVhyL6XlRu3n7Rfk2FxMeK+wRSaQ7dI=', + }); + + const serializedWithLease = algosdk.encodeUnsignedTransaction(txnWithLease); + const serializedWithoutLease = algosdk.encodeUnsignedTransaction( + txnWithoutLease + ); + + assert.deepStrictEqual(serializedWithLease, serializedWithoutLease); + }); + + it('should drop an assetMetadataHash of all zeros', () => { + const address = + 'BH55E5RMBD4GYWXGX5W5PJ5JAHPGM5OXKDQH5DC4O2MGI7NW4H6VOE4CP4'; + + const txnWithHash = new algosdk.Transaction({ + from: address, + fee: 10, + firstRound: 322575, + lastRound: 323575, + genesisHash: 'SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=', + assetIndex: 1234, + assetManager: address, + assetReserve: address, + assetFreeze: address, + assetClawback: address, + type: 'acfg', + assetMetadataHash: new Uint8Array(32), + }); + + const txnWithoutHash = new algosdk.Transaction({ + from: address, + fee: 10, + firstRound: 322575, + lastRound: 323575, + genesisHash: 'SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=', + assetIndex: 1234, + assetManager: address, + assetReserve: address, + assetFreeze: address, + assetClawback: address, + type: 'acfg', + }); + + const serializedWithHash = algosdk.encodeUnsignedTransaction(txnWithHash); + const serializedWithoutHash = algosdk.encodeUnsignedTransaction( + txnWithoutHash + ); + + assert.deepStrictEqual(serializedWithHash, serializedWithoutHash); + }); + it('should be able to prettyprint and go toString without throwing', () => { const o = { from: '7ZUECA7HFLZTXENRV24SHLU4AVPUTMTTDUFUBNBD64C73F3UHRTHAIOF6Q',