Skip to content

Conversation

@devin-ai-integration
Copy link
Contributor

Pyth Examples Contribution

Type of Contribution

  • New Example Project (Adding a new example to demonstrate Pyth integration)
  • Bug Fix (Fixing an issue in existing examples)
  • Documentation Update (Improving README, comments, or guides)
  • Enhancement (Improving existing functionality or adding features)
  • Hackathon Submission (Submitting a project from a hackathon)

Project Information

Project/Example Name: Pyth Lazer EVM Example

Pyth Product Used:

  • Pyth Price Feeds
  • Pyth Entropy
  • Multiple Products
  • Other: Pyth Lazer

Blockchain/Platform:

  • Ethereum/EVM
  • Solana
  • Aptos
  • Sui
  • Fuel
  • Starknet
  • TON
  • Other: ___________

Description

What does this contribution do?

Updates the Pyth Lazer EVM example to use the new PythLazerLib struct-based parsing approach with parseUpdateFromPayload() instead of manual low-level parsing. This provides a cleaner, more maintainable integration pattern.

Key changes:

  • Refactored ExampleReceiver.sol to use PythLazerStructs.Update and Feed structs
  • Added helper function pattern for memory-to-calldata conversion (required by the library)
  • Added safe getter functions (hasPrice(), getPrice(), etc.) for property extraction
  • Added utility functions: getCurrentPrice(), getSpread(), isPriceFresh(), setTargetFeedId()
  • Updated tests to use TransparentUpgradeableProxy for proper PythLazer initialization
  • Comprehensive README documentation with integration guide and troubleshooting

How does it integrate with Pyth?

The contract receives signed Pyth Lazer updates, verifies them via the PythLazer contract, and parses the payload using PythLazerLib.parseUpdateFromPayload() to extract structured price feed data.

What problem does it solve or demonstrate?

Demonstrates the recommended approach for integrating Pyth Lazer price feeds using the new struct-based parsing API, which is cleaner and less error-prone than manual byte parsing.

Testing & Verification

How to Test This Contribution

Prerequisites

  • Foundry installed

Setup & Run Instructions

cd lazer/evm
forge install
forge build
forge test -vv

All 5 tests pass:

  • test_updatePrice_structBased() - Main price update flow
  • test_revert_insufficientFee() - Fee validation
  • test_nonTargetFeed_noUpdate() - Non-target feed handling
  • test_setTargetFeedId() - Feed ID configuration
  • test_helperFunctions() - Utility functions

Checklist

Code Quality

  • Code follows existing patterns in the repository
  • Proper error handling implemented
  • No hardcoded values (use environment variables where appropriate)

Testing

  • Tested locally and works as expected
  • All existing functionality still works (no breaking changes)

Additional Context

Notes for Reviewers

  1. Memory-to-calldata conversion: The _parsePayload() + parsePayloadExternal() pattern is needed because PythLazerLib.parseUpdateFromPayload() expects bytes calldata but verifyUpdate() returns bytes memory. This external call pattern converts memory to calldata.

  2. Type change: price changed from uint64 to int64 to match the new library's return types.

  3. Submodule update: Updated lib/pyth-crosschain to include the new PythLazerStructs.sol file.

  4. No access control on setTargetFeedId(): This is intentional for the example to keep it simple.


Link to Devin run: https://app.devin.ai/sessions/0fee8f43574b4c9198b0dd65fe9de258
Requested by: [email protected]

…parsing

- Update ExampleReceiver.sol to use parseUpdateFromPayload() for high-level struct-based parsing
- Add helper function pattern for memory-to-calldata conversion
- Use safe getter functions (hasPrice, getPrice, etc.) for property extraction
- Add utility functions: getCurrentPrice(), getSpread(), isPriceFresh(), setTargetFeedId()
- Update tests to use TransparentUpgradeableProxy for PythLazer initialization
- Add comprehensive test cases for struct-based parsing, fee validation, and helper functions
- Update README with detailed documentation on contract architecture, tri-state property system, and integration guide
- Update pyth-crosschain submodule to include PythLazerStructs.sol

Co-Authored-By: [email protected] <[email protected]>
@devin-ai-integration
Copy link
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

/// PythLazerLib.parseUpdateFromPayload expects calldata bytes.
/// @param payload The payload bytes to parse
/// @return The parsed Update struct
function parsePayload(bytes calldata payload) external pure returns (PythLazerStructs.Update memory) {
Copy link
Member

Choose a reason for hiding this comment

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

@ali-behjati
This is something that I forgot to discuss before.

When we call an external function that returns bytes calldata, the return value gets copied to memory in the calling context. We cannot assign it directly to a calldatavariable becausecalldata` is read-only and refers specifically to the original transaction input data.

We can't do like this

(bytes calldata payload,) = pythLazer.verifyUpdate{value: verificationFee}(update);

Even though verifyUpdate declares returns (bytes calldata payload, ...), when this data crosses the external call boundary back to our/user's contract, it's returned via the ABI encoding/decoding mechanism and lands in memory, not calldata.
That's why we have to use

(bytes memory payload,) = pythLazer.verifyUpdate{value: verificationFee}(update);

The calldata return type in verifyUpdate is valid within that function (it's slicing the original update calldata), but the caller must receive it as memory.

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