Skip to content

Commit

Permalink
fix: algod to indexer txn mapping (#108)
Browse files Browse the repository at this point in the history
* fix: algod to indexer txn mapping

- Add uintName field
- Fix base64 encode
- Add extraProgramPages field

* chore: lint

* chore: fix tests

* chore: PR feedback
  • Loading branch information
PatrickDinh authored Jan 29, 2025
1 parent fab9187 commit c91f1fd
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 10 deletions.
13 changes: 6 additions & 7 deletions src/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,6 @@ export function getIndexerTransactionFromAlgodTransaction(t: TransactionInBlock,
let parentOffset = 1
const getParentOffset = () => parentOffset++

const encoder = new TextEncoder()

try {
// https://github.com/algorand/indexer/blob/main/api/converter_utils.go#L249

Expand All @@ -199,20 +197,20 @@ export function getIndexerTransactionFromAlgodTransaction(t: TransactionInBlock,
metadataHash: transaction.assetConfig.assetMetadataHash,
...(transaction.assetConfig.unitName
? {
name: transaction.assetConfig.unitName,
nameB64: encoder.encode(Buffer.from(transaction.assetConfig.unitName).toString('base64')),
unitName: transaction.assetConfig.unitName,
unitNameB64: Buffer.from(transaction.assetConfig.unitName).toString('base64'),
}
: undefined),
...(transaction.assetConfig.assetName
? {
name: transaction.assetConfig.assetName,
nameB64: encoder.encode(Buffer.from(transaction.assetConfig.assetName).toString('base64')),
nameB64: Buffer.from(transaction.assetConfig.assetName).toString('base64'),
}
: undefined),
...(transaction.assetConfig.assetURL
? {
url: transaction.assetConfig.assetURL,
urlB64: encoder.encode(Buffer.from(transaction.assetConfig.assetURL).toString('base64')),
urlB64: Buffer.from(transaction.assetConfig.assetURL).toString('base64'),
}
: undefined),
manager: transaction.assetConfig.manager?.toString(),
Expand Down Expand Up @@ -248,7 +246,7 @@ export function getIndexerTransactionFromAlgodTransaction(t: TransactionInBlock,
? {
assetTransferTransaction: new algosdk.indexerModels.TransactionAssetTransfer({
assetId: transaction.assetTransfer!.assetIndex,
amount: transaction.assetTransfer!.amount, // The amount can be undefined
amount: transaction.assetTransfer!.amount,
receiver: transaction.assetTransfer!.receiver.toString(),
sender: transaction.assetTransfer!.assetSender ? transaction.assetTransfer!.assetSender.toString() : undefined,
closeAmount: assetCloseAmount,
Expand Down Expand Up @@ -292,6 +290,7 @@ export function getIndexerTransactionFromAlgodTransaction(t: TransactionInBlock,
}
: undefined),
accounts: transaction.applicationCall!.accounts.map((a) => a),
extraProgramPages: transaction.applicationCall!.extraPages,
}),
}
: undefined),
Expand Down
18 changes: 15 additions & 3 deletions tests/filterFixture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { algorandFixture } from '@algorandfoundation/algokit-utils/testing'
import { AlgorandFixture, AlgorandFixtureConfig } from '@algorandfoundation/algokit-utils/types/testing'
import { SendAtomicTransactionComposerResults, SendTransactionResult } from '@algorandfoundation/algokit-utils/types/transaction'
import type { Account, Transaction } from 'algosdk'
import algosdk from 'algosdk'
import algosdk, { TransactionType } from 'algosdk'
import { expect, vitest } from 'vitest'
import { Arc28EventGroup, TransactionFilter, TransactionSubscriptionResult } from '../src/types'
import { GetSubscribedTransactions, SendXTransactions } from './transactions'
Expand Down Expand Up @@ -106,8 +106,20 @@ export function filterFixture(fixtureConfig?: AlgorandFixtureConfig): {

expect(algod.subscribedTransactions.length).toBe(results.length)
expect(algod.subscribedTransactions.map((s) => s.id)).toEqual(results.map((r) => r.transaction.txID()))
expect(indexer.subscribedTransactions.length).toBe(results.length)
expect(indexer.subscribedTransactions.map((s) => s.id)).toEqual(results.map((r) => r.transaction.txID()))

// Filter out the proposal payout transaction from the indexer
const subscribedTransactions = indexer.subscribedTransactions.filter(
(t) =>
!(
t.fee === 0n &&
t.confirmedRound === t.firstValid &&
t.confirmedRound === t.lastValid &&
t.txType === TransactionType.pay &&
t.parentTransactionId === undefined
),
)
expect(subscribedTransactions.length).toBe(results.length)
expect(subscribedTransactions.map((s) => s.id)).toEqual(results.map((r) => r.transaction.txID()))

return { algod, indexer }
}
Expand Down
48 changes: 48 additions & 0 deletions tests/scenarios/transform-appl-create-txn.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { AlgorandClient } from '@algorandfoundation/algokit-utils'
import { TransactionType } from 'algosdk'
import { describe, expect, it } from 'vitest'
import { GetSubscribedTransactions } from '../transactions'

describe('Application create transaction', () => {
const txnId = 'ZCQ5OCGWV253DIN5XVJTFNWVVTOQ6PYOUI3KH7ORQISLN4PEXIGQ'
const roundNumber = 31171197n
const algorand = AlgorandClient.mainNet()

it('Can have an app create transaction subscribed correctly from indexer', async () => {
const indexerTxns = await GetSubscribedTransactions(
{
filters: {
type: TransactionType.appl,
},
roundsToSync: 1,
currentRound: roundNumber + 1n,
syncBehaviour: 'catchup-with-indexer',
watermark: roundNumber - 1n,
},
algorand,
)

const txn = indexerTxns.subscribedTransactions.find((txn) => txn.id === txnId)
expect(txn).toBeDefined()
expect(txn!.createdApplicationIndex).toBe(1167143153n)
})

it('Can have an app create transaction subscribed correctly from algod', async () => {
const algodTxns = await GetSubscribedTransactions(
{
filters: {
type: TransactionType.appl,
},
roundsToSync: 1,
currentRound: roundNumber + 1n,
syncBehaviour: 'sync-oldest',
watermark: roundNumber - 1n,
},
algorand,
)

const txn = algodTxns.subscribedTransactions.find((txn) => txn.id === txnId)
expect(txn).toBeDefined()
expect(txn!.createdApplicationIndex).toBe(1167143153n)
})
})
69 changes: 69 additions & 0 deletions tests/scenarios/transform-asset-config-txn.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { AlgorandClient } from '@algorandfoundation/algokit-utils'
import { TransactionType } from 'algosdk'
import { describe, expect, it } from 'vitest'
import { getSubscribedTransactionForDiff } from '../subscribed-transactions'
import { GetSubscribedTransactions } from '../transactions'

describe('Asset config transaction', () => {
const txnId = 'QHMYTRW27O7KYP6W3SMC3HP55DN5IL2H7Z27T2YDCNFCLXOVFOJQ'
const roundNumber = 44322184n
const algorand = AlgorandClient.mainNet()

const expectedAssetCreateData = {
assetId: 0n,
params: {
creator: 'ATPVJYGEGP5H6GCZ4T6CG4PK7LH5OMWXHLXZHDPGO7RO6T3EHWTF6UUY6E',
decimals: 6,
total: 2000000000000000n,
clawback: 'ATPVJYGEGP5H6GCZ4T6CG4PK7LH5OMWXHLXZHDPGO7RO6T3EHWTF6UUY6E',
defaultFrozen: false,
freeze: 'ATPVJYGEGP5H6GCZ4T6CG4PK7LH5OMWXHLXZHDPGO7RO6T3EHWTF6UUY6E',
manager: 'ATPVJYGEGP5H6GCZ4T6CG4PK7LH5OMWXHLXZHDPGO7RO6T3EHWTF6UUY6E',
name: 'Fry Node',
nameB64: 'RnJ5IE5vZGU=',
reserve: 'ATPVJYGEGP5H6GCZ4T6CG4PK7LH5OMWXHLXZHDPGO7RO6T3EHWTF6UUY6E',
unitName: 'fNODE',
unitNameB64: 'Zk5PREU=',
url: 'https://frynetworks.com/',
urlB64: 'aHR0cHM6Ly9mcnluZXR3b3Jrcy5jb20v',
},
}

it('Can have an asset create with uint name transaction subscribed correctly from indexer', async () => {
const indexerTxns = await GetSubscribedTransactions(
{
filters: {
type: TransactionType.acfg,
},
roundsToSync: 1,
currentRound: roundNumber + 1n,
syncBehaviour: 'catchup-with-indexer',
watermark: roundNumber - 1n,
},
algorand,
)

const txn = indexerTxns.subscribedTransactions.find((txn) => txn.id === txnId)
expect(txn).toBeDefined()
expect(getSubscribedTransactionForDiff(txn!).assetConfigTransaction).toMatchObject(expectedAssetCreateData)
})

it('Can have an asset create with uint name transaction subscribed correctly from algod', async () => {
const algodTxns = await GetSubscribedTransactions(
{
filters: {
type: TransactionType.acfg,
},
roundsToSync: 1,
currentRound: roundNumber + 1n,
syncBehaviour: 'sync-oldest',
watermark: roundNumber - 1n,
},
algorand,
)

const txn = algodTxns.subscribedTransactions.find((txn) => txn.id === txnId)
expect(txn).toBeDefined()
expect(getSubscribedTransactionForDiff(txn!).assetConfigTransaction).toMatchObject(expectedAssetCreateData)
})
})
1 change: 1 addition & 0 deletions tests/scenarios/transform-complex-txn.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ describe('Complex transaction with many nested inner transactions', () => {
"applicationId": 1390675395n,
"approvalProgram": "",
"clearStateProgram": "",
"extraProgramPages": 0,
"foreignApps": [],
"foreignAssets": [
1390638935n,
Expand Down

0 comments on commit c91f1fd

Please sign in to comment.