Skip to content

Cardano - Eryx Raccoons#107

Open
jdiaz-eryx wants to merge 56 commits intopyth-network:mainfrom
eryxcoop:main
Open

Cardano - Eryx Raccoons#107
jdiaz-eryx wants to merge 56 commits intopyth-network:mainfrom
eryxcoop:main

Conversation

@jdiaz-eryx
Copy link
Copy Markdown

@jdiaz-eryx jdiaz-eryx commented Mar 22, 2026

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 Product Used:

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

Blockchain/Platform:

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

Description

What does this contribution do?

Hackaton Submission

How does it integrate with Pyth?

Uses Pyth offchain API and Cardano contracts

What problem does it solve or demonstrate?

Explained in project's readme

Directory Structure (for new examples)

Explained in project's readme

Testing & Verification

How to Test This Contribution

Explained in project's readme

Prerequisites

Explained in project's readme

Setup & Run Instructions

Explained in project's readme

Deployment Information (if applicable)

Explained in project's readme

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

Related Issues

Screenshots/Demo (if applicable)

Explained in project's readme

Notes for Reviewers

Explained in project's readme

Thank you for contributing to Pyth Examples!


Open with Devin

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 2 potential issues.

View 7 additional findings in Devin Review.

Open in Devin Review

Comment on lines +275 to +278
.payToAddress({
address: Address.fromBech32(params.sponsorAddress),
assets: Assets.fromLovelace(lovelaceToSponsor),
})
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔴 Unlock transaction fails when sponsor's remaining share is zero or below Cardano's minimum UTxO

The buildUnlockTxFromData function unconditionally creates a payment output to the sponsor for lovelaceToSponsor = totalLovelace - lovelaceToUser. When the ADA/USD price drops significantly (approaching the coverage multiplier threshold, e.g. ~50% for a 2x multiplier), lovelaceToUser approaches or equals totalLovelace, making lovelaceToSponsor zero or below Cardano's minimum UTxO requirement (~1-2 ADA). Cardano ledger rules reject any transaction output below the minimum UTxO, so the build() call will fail. This means legitimate unlock claims become impossible when the locked collateral barely covers the USD-equivalent owed to the user — the funds remain permanently locked until a cancel is performed. The on-chain validator (pay_with_pyth.ak:54-59) does NOT require a sponsor output — it only checks lovelace_of(output.value) >= lovelace_to_user for the user address — so the fix is to skip the sponsor output when lovelaceToSponsor is below the minimum UTxO threshold.

Prompt for agents
In lazer/cardano/backend/deployment/transactions/unlock.ts, around lines 249-278 in buildUnlockTxFromData, the sponsor payment output is unconditionally created. When lovelaceToSponsor is 0 or below the minimum UTxO value (~1_000_000 lovelace), this creates an invalid Cardano transaction output that will be rejected by the ledger.

Fix: After computing lovelaceToSponsor on line 249, add a constant like MIN_UTXO_LOVELACE = 1_000_000n (or a more precise estimate). Then conditionally build the transaction: only include the .payToAddress for the sponsor (lines 275-278) when lovelaceToSponsor >= MIN_UTXO_LOVELACE. When it's below the threshold but above 0, the small remainder can either be added to the user's output (lovelaceToUser += lovelaceToSponsor) or left as transaction fee. When it's exactly 0, simply omit the sponsor output. Update the check at line 244 accordingly — if lovelaceToUser > totalLovelace - MIN_UTXO_LOVELACE and lovelaceToUser <= totalLovelace, all locked ADA should go to the user with no sponsor output.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +84 to +89
const lockedAda = useMemo(
() =>
requests
.filter((request) => request.status !== 'claimed')
.reduce((sum, request) => sum + request.lockAda, 0),
[requests],
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 "Open locked collateral" metric incorrectly includes cancelled requests

The lockedAda computation at App.tsx:84-89 filters out only claimed requests (request.status !== 'claimed'), which means cancelled requests are still counted. Once a request is cancelled, the sponsor has reclaimed the ADA from the script address — those funds are no longer locked on-chain. This inflates the "Open locked collateral" metric displayed to users. The SponsorDashboard at lazer/cardano/frontend/src/screens/SponsorDashboard.tsx:12-13 correctly excludes both claimed and cancelled statuses for its own metrics.

Suggested change
const lockedAda = useMemo(
() =>
requests
.filter((request) => request.status !== 'claimed')
.reduce((sum, request) => sum + request.lockAda, 0),
[requests],
const lockedAda = useMemo(
() =>
requests
.filter((request) => request.status !== 'claimed' && request.status !== 'cancelled')
.reduce((sum, request) => sum + request.lockAda, 0),
[requests],
);
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

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.

3 participants