Skip to content
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

fix: algod to indexer txn mapping #108

Merged
merged 4 commits into from
Jan 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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