diff --git a/src/appAccess.ts b/src/appAccess.ts index 5d8b6f747..6ab5e1cd8 100644 --- a/src/appAccess.ts +++ b/src/appAccess.ts @@ -145,11 +145,12 @@ export function convertIndicesToResourceReferences( if (!hAssetIndex) { throw new Error(`Holding missing asset index: ${holding}`); } + const hAddress = hAddressIndex === 0 ? Address.zeroAddress() - : (references[hAddressIndex - 1].address as Address); - const asset = references[hAssetIndex - 1].assetIndex as bigint; + : (accessList[hAddressIndex - 1].get('d') as Address); + const asset = accessList[hAssetIndex - 1].get('s') as bigint; references.push({ holding: { address: hAddress, assetIndex: asset } }); continue; } @@ -160,11 +161,11 @@ export function convertIndicesToResourceReferences( const lAddress = lAddressIndex === 0 ? Address.zeroAddress() - : (references[lAddressIndex - 1].address as Address); + : (accessList[lAddressIndex - 1].get('d') as Address); const app = lAppIndex === 0 ? BigInt(0) - : (references[lAppIndex - 1].appIndex as bigint); + : (accessList[lAppIndex - 1].get('p') as bigint); references.push({ locals: { address: lAddress, appIndex: app } }); continue; } @@ -178,7 +179,7 @@ export function convertIndicesToResourceReferences( const app = bAppIndex === 0 ? BigInt(0) - : (references[bAppIndex - 1].appIndex as number | bigint); + : (accessList[bAppIndex - 1].get('p') as number | bigint); references.push({ box: { appIndex: app, name } }); } } diff --git a/tests/5.Transaction.ts b/tests/5.Transaction.ts index 5ed778ee7..fc696d72f 100644 --- a/tests/5.Transaction.ts +++ b/tests/5.Transaction.ts @@ -2911,4 +2911,58 @@ describe('Application Resources References', () => { assert.ok((localsRef.locals.address as algosdk.Address).equals(addr1)); }); }); + + it('should decode access list', () => { + const addr1 = algosdk.Address.fromString( + 'FDMKB5D72THLYSJEBHBDHUE7XFRDOM5IHO44SOJ7AWPD6EZMWOQ2WKN7HQ' + ); + const txn = algosdk.makeApplicationCallTxnFromObject({ + sender: 'BH55E5RMBD4GYWXGX5W5PJ5JAHPGM5OXKDQH5DC4O2MGI7NW4H6VOE4CP4', + appIndex: 111, + onComplete: algosdk.OnApplicationComplete.NoOpOC, + access: [ + { + holding: { + assetIndex: 123, + address: addr1, + }, + }, + { address: addr1 }, + { assetIndex: 123 }, + ], + suggestedParams: { + minFee: 1000, + fee: 0, + firstValid: 322575, + lastValid: 323575, + genesisID: 'testnet-v1.0', + genesisHash: algosdk.base64ToBytes( + 'SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=' + ), + }, + }); + + const encodingData = txn.toEncodingData(); + + // This code is here to demonstrate the problem. + // When encoding, the cross product references are added first, + // so modify the access list encoding data to simulate how it may be encoded on chain. + const accessList = encodingData.get('al') as Array>; + // Index 2 is actually the holding reference. + // Manually adjust the indexes, because we'll be re-ording the list. + (accessList[2].get('h') as any).set('d', 2); + (accessList[2].get('h') as any).set('s', 3); + const updateAccessList: Array> = []; + updateAccessList.push(accessList[2]); + updateAccessList.push(accessList[0]); + updateAccessList.push(accessList[1]); + encodingData.set('al', updateAccessList); + + const decodedTxn = algosdk.Transaction.fromEncodingData(encodingData); + + assert.deepStrictEqual( + txn.applicationCall?.access, + decodedTxn.applicationCall?.access + ); + }); });