Skip to content

Commit

Permalink
feat: track when balance was last updated from rpc
Browse files Browse the repository at this point in the history
- be smart when to query from rpc again
- avoid double rpc calling in the same block
  • Loading branch information
kasparkallas committed May 30, 2024
1 parent 41f6e67 commit 6437cd9
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 16 deletions.
5 changes: 5 additions & 0 deletions packages/subgraph/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -2417,6 +2417,11 @@ type AccountTokenSnapshot @entity {
"""
balanceUntilUpdatedAt: BigInt!

"""
The last block the balance was queried from an RPC (the most accurate source for balance data).
"""
balanceLastUpdatedFromRpcBlocknumber: BigInt

"""
The total deposit this account has held by all flow agreements for `account` active streams.
"""
Expand Down
48 changes: 32 additions & 16 deletions packages/subgraph/src/mappingHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -981,23 +981,39 @@ function updateATSBalanceAndUpdatedAt(
Address.fromString(accountTokenSnapshot.token)
);

if (balanceDelta && !accountTokenSnapshot.isLiquidationEstimateOptimistic) {
accountTokenSnapshot.balanceUntilUpdatedAt =
accountTokenSnapshot.balanceUntilUpdatedAt.plus(
balanceDelta as BigInt
);
} else {
// if the account has any subscriptions with units we assume that
// the balance data requires a RPC call for balance because we did not
// have claim events there and we do not count distributions
// for subscribers
const newBalanceResult = superTokenContract.try_realtimeBalanceOf(
Address.fromString(accountTokenSnapshot.account),
block.timestamp
);
if (!newBalanceResult.reverted) {
// If the balance has been updated from RPC in this block then no need to update it again.
// The RPC call gets the final balance from that block.
if (accountTokenSnapshot.balanceLastUpdatedFromRpcBlocknumber !== block.number) {

// "Unpredictable" would mean an account receiving GDA distributions, IDA distributions or GDA adjustment flow.
// The reason they are "unpredictable" is that it would be unscalable to perfectly keep track of them with subgraph.
// What makes it unscalable is that the distribution events happen on the side of the distributor, not the receiver.
// We can't iterate all the receivers when a distribution is made.
const isAccountWithOnlyPredictableBalanceSources = !accountTokenSnapshot.isLiquidationEstimateOptimistic;

// If the balance has been updated in this block without an RPC, it's better to be safe than sorry and just get the final accurate state from the RPC.
const hasBalanceBeenUpdatedInThisBlock = accountTokenSnapshot.updatedAtBlockNumber === block.number;

if (balanceDelta && isAccountWithOnlyPredictableBalanceSources && !hasBalanceBeenUpdatedInThisBlock) {
accountTokenSnapshot.balanceUntilUpdatedAt =
newBalanceResult.value.value0;
accountTokenSnapshot.balanceUntilUpdatedAt.plus(
balanceDelta as BigInt
);
} else {
// if the account has any subscriptions with units we assume that
// the balance data requires a RPC call for balance because we did not
// have claim events there and we do not count distributions
// for subscribers
const newBalanceResult = superTokenContract.try_realtimeBalanceOf(
Address.fromString(accountTokenSnapshot.account),
block.timestamp
);
if (!newBalanceResult.reverted) {
accountTokenSnapshot.balanceUntilUpdatedAt =
newBalanceResult.value.value0;
} else {
accountTokenSnapshot.balanceLastUpdatedFromRpcBlocknumber = block.number;
}
}
}

Expand Down

0 comments on commit 6437cd9

Please sign in to comment.