algokit-subscriber-ts

v3 migration

This release updates the subscriber library to support algosdk@3. As a result the majority of the changes are to support this.

For further information about algosdk@3, see migration guide for algosdk@3.

Details of this release are available here

Type Changes

In both @algorandfoundation/algokit-utils and subscriber we follow a general pattern of leveraging algosdk functionality and types where possible. The algosdk@3 changes introduce a number of new types, which allow both @algorandfoundation/algokit-utils and the subscriber library to leverage them. Below are the main type related changes which need to be considered when following the migration steps.

Changes to SubscribedTransaction

Previously SubscribedTransaction extended TransactionResult from @algorandfoundation/algokit-utils, however now @algorandfoundation/algokit-utils leverages the algosdk@3 types directly. As a result SubscribedTransaction now extends algosdk.indexerModels.Transaction from algosdk@3. The changes needed to support this are described below.

// The example below attemps to access data from an asset transfer transaction

/**** Before ****/
if (subscribedTransaction['tx-type'] === TransactionType.axfer) {
  console.log('assetId', subscribedTransaction['asset-transfer-transaction']['asset-id'])
}
// Result:
//  assetId: 31566704

/**** After ****/
if (subscribedTransaction.txType === TransactionType.axfer) {
  console.log('assetId', subscribedTransaction.assetTransferTransaction.assetId)
}
// Result:
//  assetId: 31566704n <- this is now a bigint

Changes to TransactionInBlock

This type has had several changes, mainly to make this type more aligned with SubscribedTransaction:

Removal of BlockData

Previously a custom BlockData type was used to represent a raw algosdk block, as algosdk@2 didn’t export a suitable one. Now that algosdk@3 does, algosdk.modelsv2.BlockResponse replaces BlockData. In algosdk@3, you can get the algosdk.modelsv2.BlockResponse from algod client as below.

const block = await algodClient.block(round).do()

Removal of BlockTransaction and BlockInnerTransaction

The BlockTransaction and BlockInnerTransaction types were removed and all usages of this type, have been replaced with algosdk.SignedTxnWithAD from algosdk@3.

Previously BlockTransaction and BlockInnerTransaction represented the raw algod block transaction returned when calling await algodClient.block(round).do(). In algosdk@3 calling await algodClient.block(round).do() returns a processed version of the response with SignedTxnWithAD nested inside, hence why we have replaced BlockTransaction and BlockInnerTransaction. The below code shows some usages examples.

// To get the created asset ID from a block transaction

/**** Before ****/
console.log('created asset ID', blockTransaction.caid)
// Result:
//   created asset ID: 31566704

/**** After ****/
console.log('created asset ID', signedTxnWithAD.applyData.configAsset)
// Result:
// created asset ID: 31566704n <- this is a bigint
// To access the transaction sender

/**** Before ****/
console.log('transaction sender', blockTransaction.txn.snd)
// Result:
// transaction sender: 25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE

/**** After ****/
// The sender now has `Address` type
console.log('transaction sender', signedTxnWithAD.signedTxn.txn.sender.toString())
// Result:
// transaction sender: 25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE

Changes to BlockMetadata

This type has not changed much, except for some fields have been converted from number to bigint to align with algosdk@3.

Changes to BalanceChange

This type has not changed much, except for some fields have been converted from number to bigint to align with algosdk@3.

Migration Steps

Step 1 - Update usages of AlgorandSubscriber and getSubscribedTransactions

Since the types exported are now mostly aligned with algosdk@3, relevant number fields are now bigint. To maintain consistency, relevant filters that passed a number should now use a bigint.

/**** Before ****/
const subscriber = new AlgorandSubscriber(
  {
    filters: [
      {
        name: 'usdc',
        filter: {
          type: TransactionType.axfer,
          assetId: 31566704,
          minAmount: 1_000_000,
        },
      },
    ],
    // ...
  },
  algorand.client.algod,
)

/**** After ****/
const subscriber = new AlgorandSubscriber(
  {
    filters: [
      {
        name: 'usdc',
        filter: {
          type: TransactionType.axfer,
          assetId: 31566704n, // this is now a bigint
          minAmount: 1_000_000n, // this is now a bigint
        },
      },
    ],
    // ...
  },
  algorand.client.algod,
)

subscriber.on('usdc', (subscribedTransaction) => {
  // Handling logic goes here
})
/**** Before ****/
const result = await getSubscribedTransactions(
  {
    filters: [
      {
        name: 'usdc',
        filter: {
          type: TransactionType.axfer,
          assetId: 31566704n,
          minAmount: 1_000_000n,
        },
      },
    ],
    syncBehaviour: 'skip-sync-newest',
    watermark: 100n,
  },
  algorand.client.algod,
)

/**** After ****/
const result = await getSubscribedTransactions(
  {
    filters: [
      {
        name: 'usdc',
        filter: {
          type: TransactionType.axfer,
          assetId: 31566704n, // this is now a bigint
          minAmount: 1_000_000n, // this is now a bigint
        },
      },
    ],
    syncBehaviour: 'skip-sync-newest',
    watermark: 100n,
  },
  algorand.client.algod,
)

result.subscribedTransactions.forEach((subscribedTransaction) => {
  // Handling logic goes here
})

The SubscribedTransaction returned from your subscriber now leverage the algosdk@3 types, so your handling code will require updates to account for these changes. See Changes to SubscribedTransaction for details on how to update.

Step 2 - Update usages of getBlockTransactions

The previous input type Block has been changed to algosdk.modelsv2.BlockResponse, see Removal of BlockData for more information. The output type TransactionInBlock has been updated to support the algosdk@3 types, see Changes to TransactionInBlock for more information.

/**** Before ****/
// The algod client returns a `Record<string, any>` value
const blockData = (await algorand.client.algod.block(round).do()) as BlockData
const blockTransactions = getBlockTransactions(blockData.block)

/**** After ****/
const block = await algorand.client.algod.block(round).do()
const blockTransactions = getBlockTransactions(block)

Step 3 - Update usages of getIndexerTransactionFromAlgodTransaction

The input type TransactionInBlock has been updated to support the algosdk@3 types, see Changes to TransactionInBlock for more information. The output type SubscribedTransaction has been updated to support the algosdk@3 types, see Changes to SubscribedTransaction for more information.

Step 4 - Update usages of blockDataToBlockMetadata

This method has been renamed to blockResponseToBlockMetadata. Additionally the previous input type BlockData has been changed to algosdk.modelsv2.BlockResponse, see Removal of BlockData for more information. The output type BlockMetadata has been changed in a few small ways, see Changes to BlockMetadata for more information.

/**** Before ****/
// The algod client returns a `Record<string, any>` value
const blockData = (await algorand.client.algod.block(round).do()) as BlockData
const blockMetadata = blockDataToBlockMetadata(blockData)

/**** After ****/
const block = await algorand.client.algod.block(round).do()
const blockMetadata = blockResponseToBlockMetadata(block)

Step 5 - Update usages of extractBalanceChangesFromBlockTransaction

The previous input type BlockTransaction | BlockInnerTransaction has been changed to algosdk.SignedTxnWithAD, see Removal of BlockTransaction and BlockInnerTransaction for more information. The output type BalanceChange has been changed in a few small ways, see Changes to BalanceChange for more information.

Step 6 - Update usages of extractBalanceChangesFromIndexerTransaction

The previous input type TransactionResult has been changed to algosdk.indexerModels.Transaction, see Changes to SubscribedTransaction for more information. The output type BalanceChange[] has been changed in a few small ways, see Changes to BalanceChange for more information.

Step 7 - Update usages of getBlocksBulk

The previous return type BlockData has been changed to algosdk.modelsv2.BlockResponse, see Removal of BlockData for more information.

Step 8 - Handle bigint serialization

Since the majority of number fields are now bigint, the default JSON.stringify will no longer work in scenarios where it previously did. We recommend you use a custom JSON replacer to handle the bigint values. Below is an example of how you might do this.

export const asJson = (value: unknown) => JSON.stringify(value, (_, v) => (typeof v === 'bigint' ? v.toString() : v), 2)