algorandfoundation / algokit-subscriber-ts

Simple, but flexible / configurable Algorand transaction subscription / indexing mechanism
MIT License
12 stars 6 forks source link

Detect and subscribe to balance changes #17

Closed joe-p closed 6 months ago

joe-p commented 6 months ago

It would be useful to have a "balance change" event. A common use case for a lib like this is monitoring for asset/ALGO transfers, but doing so properly is a bit complicated since you need to check the aamt and aca fields, which is likely unexpected for someone not familiar with how asset closing works on Algorand.

I'm thinking the event could return the following, with the number being the delta (could be negative) of the balance for the given asset. ALGO would be asset 0.

{
    [addr: string]: { [asset: number]: number };
}
robdmoore commented 6 months ago

Should we recursively process this into inner transactions or require that you read inner transactions to see if there are balance changes?

joe-p commented 6 months ago

I would think it should process inners as well. I assume that's what subscribing to specific transaction types do right now, no?

robdmoore commented 6 months ago

Terminology clarification:

event in this library is a user-specified concept, what I think you are asking is we add a balanceChange filter (and then also add balanceChanges to the SubscribedTransaction return object).

What we may also need to do with this is add a balance change filter, and potentially add an account(s) filter too so you can search for an account(s) that exist in sender, receiver or close amount to (you can specify sender and receiver as filters but the logic is AND logic , not OR logic).

robdmoore commented 6 months ago

I would think it should process inners as well. I assume that's what subscribing to specific transaction types do right now, no?

We already allow subscribing to inners with filters, I more meant if a balanceChange field on the subscribed transaction should have balances calculated recursively or just for that single transaction.

joe-p commented 6 months ago

Ahh ok I was thinking of an alternative to SubscribedTransaction. But adding balanceChanges to SubscribedTransaction makes more sense. Aggregation can be done at a higher level. Having it done per (inner) transaction makes since.

For example, an appl will always just have a balance change equal to 0 - fee for the sender, even if there are inners within the appl

robdmoore commented 6 months ago

Oh wow, I didn't think of fees. Balance changes are complex hey :P

robdmoore commented 6 months ago

One thing to note: this feature is likely to be exceedingly difficult to work with indexer catchup, so it's possible we may have to make this one algod only...

robdmoore commented 6 months ago

I was thinking of an alternative to SubscribedTransaction

Understand the thinking, but it breaks the model of how this library works, however, it's easy enough to get the exact effect you want with the mapper https://github.com/algorandfoundation/algokit-subscriber-ts/blob/main/src/types/subscription.ts#L222, which would allow you to expose just the balanceChange field (when it exists).

joe-p commented 6 months ago

I think the fields we need to take note of are:

fee for all txns receiver for pay/axfer xferAsset for axfers xferAmount for axfers assetCloseTo for axfers assetCloseAmount for axfers closeRemainderTo for all txns sender for payments sender OR assetSender for axfers

Also once we have incentives I believe there will be a payment associated with keyreg

joe-p commented 6 months ago

One thing to note: this feature is likely to be exceedingly difficult to work with indexer catchup, so it's possible we may have to make this one algod only...

How come?

robdmoore commented 6 months ago

because you can't search indexer for closeRemainderTo (I think?)

robdmoore commented 6 months ago

and otherwise the number of transactions returned will be way too high

robdmoore commented 6 months ago

yeah image

robdmoore commented 6 months ago

it would be possible to support it for an asset, but not algos I suspect (could prefilter for txtype: axfer and assetId, then postfilter for balance changes)

robdmoore commented 6 months ago

Maybe we support subscribing to balance changes of an asset, but only show algo balance changes of a subscribed transaction?

joe-p commented 6 months ago

because you can't search indexer for closeRemainderTo (I think?)

Ok interesting. I had assumed this library worked by getting the full block and then parsing client side. Didn't realize it was indexer queries. Seems like something the indexer should be updated to support.

it would be possible to support it for an asset, but not algos I suspect (could prefilter for txtype: axfer and assetId, then postfilter for balance changes)

We're still missing assetCloseTo though

robdmoore commented 6 months ago

Ok interesting. I had assumed this library worked by getting the full block and then parsing client side.

It does, it just also has an indexer catchup mode, see: https://github.com/algorandfoundation/algokit-subscriber-ts/blob/main/docs/README.md#fast-initial-index for context.

robdmoore commented 6 months ago

We're still missing assetCloseTo though

Yes, but that can be done in post-filter in-memory.

When indexer catchup is used there is a pre-filter to indexer search and then a post filter in-memory, see here: https://github.com/algorandfoundation/algokit-subscriber-ts/blob/main/src/subscriptions.ts#L106-L109

joe-p commented 6 months ago

Yes, but that can be done in post-filter in-memory.

But we need it in the initial filter. If I want to monitor Alice for incoming assets, I need to get all transactions that have assetCloseTo: Alice

robdmoore commented 6 months ago

Yeah you wouldn't be able to do that, so we'd have to prefilter for the asset. Naturally for some assets that's going to be too many transactions and thus not practical and in that case you'd have to use algod only or not catch up from the start of the chain.

If we can get assetCloseTo and closeRemainderTo support in indexer that would certainly be neat!

robdmoore commented 6 months ago

As part of this we should probably include the following filters:

senderOrReceiver closeTo hasBalanceChange

And it should be able to apply to both pay or axfer depending on which was specified in the filter.