Conversation
|
The event is only emitted inside Could Another option would be to calculate position health off-chain entirely.
|
|
@holyfuchs Thanks for starting this discussion!
Yes, we could write a batch script, but it only mitigates the problem rather than solving it:
I think it adds significant complexity - we'd need to replicate the health calculation logic off-chain, keep it in sync with any contract changes, and independently fetch and combine interest indices + oracle prices + per-position balances. I think events are a much simpler and more maintainable approach, and I'd prefer to go with it and only fall back to scripts if events turn out not to be doable for some reason. |
Yes, but this only queues positions when the
Scripts can't persist state changes, but they do reflect them during execution.
Position health changes constantly — every second due to interest accrual, and on every price tick. Events are only useful if you emit one regularly for every position. You could add a function that iterates all positions and emits health events on a schedule, but unlike a script this isn't free — each event costs gas, so at any meaningful scale this gets expensive fast. Scripts are cheaper here precisely because they don't write to chain.
I agree it definitely adds a significant amount of complexity but I don't think there is a nice solution here. |
|
@holyfuchs thanks for the reply! After syncing with @vishalchangrani, it looks like tracking health factors for all positions is only a temporary requirement. Given that, we probably don’t need to worry about scaling here and can stick with a script-based approach for now. That said, there’s a separate issue: fcm-observer is stateless, so after a restart/redeploy we lose the IDs of previously opened positions. I see a couple of ways to recover them:
Curious if you have thoughts on this, or if there’s a better pattern I'm missing here. |
|
Ran a small test and for bigger resource in the map it fails at > 150k keys. So adding that function should be fine. |
| } | ||
|
|
||
| let positionHealth = self.positionHealth(pid: pid) | ||
| emit PositionHealthUpdated(pid: pid, health: positionHealth) |
There was a problem hiding this comment.
I wonder how do we ensure that we've captured all the cases where the position health is updated. Note, this function has a few returns that skips this emit.
And is it possible the position health will be updated outside of this function?
This function only queues the update, asyncUpdatePosition is actually the function updating the position. Should we emit event there instead?
And this is when the position is updated from internally. What about externally? For instance, since position health depends on the price oracle, so the position health is changed as soon as the price oracle updates the price.
There was a problem hiding this comment.
Your concerns are valid and discussed in this PR. This PR is to be closed. We're going to gather position health factors via a script.
|
We decided to move on with a script-based approach. |
Motivation
The FCM observer currently fetches positions’ health by running scripts (
get_position_by_id.cdc). This approach doesn’t scale well.For example, with ~10,000 positions, we need to execute 10,000 script calls. Access nodes are rate-limited (typically ~1–5 requests/sec), so processing all positions takes a significant amount of time.
Change
Result