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

pulse-scheduler: init ethereum contracts, subscriptions, updating prices #2572

Open
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

tejasbadadare
Copy link
Contributor

@tejasbadadare tejasbadadare commented Apr 9, 2025

Summary

Initialize the Pulse Scheduler Ethereum contracts with a base layer of functionality. Follows the structure/boilerplate of the existing Pulse contracts.

Rationale

Add state, functions, and tests for:

  • Subscription management
    • Only manager can CRUD subscriptions
  • Pushing and consuming price updates
    • An update to a subscription's feeds must have matching timestamps and contain all price IDs for that subscription.
    • Since we plan to make updating permissionless, an update is only allowed if the update criteria is met.
    • Only whitelisted readers can consume the price feeds.
  • Viewing active subscriptions (for keepers)

How has this been tested?

  • Current tests cover my changes
  • Added new tests
  • Manually tested the code

Up next

  • Balance management (actually using manager funds)
  • Keeper/provider management (payment/registration, etc)
  • Gas strategy configuration
  • Gas benchmark tests

Copy link

vercel bot commented Apr 9, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
api-reference ✅ Ready (Inspect) Visit Preview 💬 Add feedback Apr 14, 2025 4:46pm
insights ✅ Ready (Inspect) Visit Preview 💬 Add feedback Apr 14, 2025 4:46pm
proposals ✅ Ready (Inspect) Visit Preview 💬 Add feedback Apr 14, 2025 4:46pm
staking ✅ Ready (Inspect) Visit Preview 💬 Add feedback Apr 14, 2025 4:46pm
2 Skipped Deployments
Name Status Preview Comments Updated (UTC)
component-library ⬜️ Ignored (Inspect) Visit Preview Apr 14, 2025 4:46pm
entropy-debugger ⬜️ Ignored (Inspect) Visit Preview Apr 14, 2025 4:46pm

@tejasbadadare tejasbadadare changed the title Tb/pulse scheduler/init pulse-scheduler: init ethereum contracts Apr 9, 2025
@tejasbadadare tejasbadadare changed the title pulse-scheduler: init ethereum contracts pulse-scheduler: init ethereum contracts, subscriptions, updating prices Apr 9, 2025
- Updated price feed parsing to allow for a timestamp range of [-10s, now].
- Introduced validation for update conditions, including checks for heartbeat and price deviation.
- Added new error handling for outdated timestamps and unmet update conditions.
- Refactored subscription status to use a uint256 for last updated timestamp.
- Expanded test coverage for update conditions and validation scenarios.
Copy link
Contributor

@jayantk jayantk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like a good start to me. Feel free to address my comments in follow up PRs, as this is pretty big and it's generally fine to merge as is.

Please do let @ali-bahjati take a look before merging though.


contract SchedulerState {
// Maximum number of price feeds per subscription
uint8 public constant MAX_PRICE_IDS = 10;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this a reasonable limit? Seems like lending protocols could want more than 10 feeds ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah it's an arbitrary number, will raise it to something higher

_state.subscriptionNumber = 1;
}

function addSubscription(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggest making this payable and having it call addFunds automatically. If you don't do that, then users will need to either do 2 transactions to create & fund a subscription (or use a multicall contract, which are available on some chains but not others...)

// We will validate the trigger conditions and timestamps ourselves
// using the returned PriceFeeds.
uint64 maxPublishTime = SafeCast.toUint64(block.timestamp);
uint64 minPublishTime = maxPublishTime - 10 seconds;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm not sure 10 seconds is enough. Either way, you probably want this value to be configurable by the admin authority.

Copy link
Contributor Author

@tejasbadadare tejasbadadare Apr 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah true, will set it to 1 minute as default to allow for retries/flaky RPCs which might result in the tx landing later than expected.

validPriceId = true;
break;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fyi instead of doing this loop, you can also check if requestedFeeds[i] is all zero below. (or check 1 field of it which is guaranteed to be nonzero in a valid update).

That approach also works better in the rare case where someone makes a subscription then tries to read it before it's ever updated.

{
// TODO: This is gonna be expensive because we're iterating through
// all subscriptions, including deactivated ones. But because its a view
// function maybe it's not bad? We can optimize this.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah there may be some maximum size limit on the result (?) may need to paginate this or something like that

I also worry that there's a potential vulnerability here where someone goes and creates a billion subscriptions. If there are too many subscriptions, then maybe the keeper can't find the active ones, and that causes the service to go down.

emit SubscriptionUpdated(subscriptionId);
}

function deactivateSubscription(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be a special case of updateSubscription -- then you can also re-activate deactivated subscriptions?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, when writing this I had considered deactivating a subscription to be a one-way operation. But it is better UX to allow someone to pause their subscription but maintain the balance and settings, so they can resume later. To make it a special case of updateSubscription, we'd need to move isActive from SubscriptionStatus to SubscriptionParams, which maybe feels a little strange from a data model perspective. I considered adding a updateSubscriptionIsActive(isActive: bool), but I think i prefer just one unified updateSubscription(). Will make that change

scheduler.updatePriceFeeds(subscriptionId, updateData2, priceIds);
}

function testUpdatePriceFeedsRevertsOnUpdateConditionsNotMet_Deviation()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's with the _ in the name here and in the method above

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants