feat(cardano): LemonPyth - RWA Peg Defense with Aiken & Pyth Lazer#105
feat(cardano): LemonPyth - RWA Peg Defense with Aiken & Pyth Lazer#105MattSZdev wants to merge 2 commits intopyth-network:mainfrom
Conversation
| { hex: "0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43", symbol: 'BTC', network: 'Bitcoin' }, | ||
| { hex: "0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace", symbol: 'ETH', network: 'Ethereum' }, | ||
| { hex: "0x2a01deaec9e51a579277b34b122399984d0bbf57e2458a7e42fecd2829867a0d", symbol: 'ADA', network: 'Cardano' } |
There was a problem hiding this comment.
🔴 Pyth Hermes API feed ID lookup always fails due to '0x' prefix mismatch
The FEEDS array stores hex IDs with a 0x prefix (e.g. "0xe62df6c8...") but the Pyth Hermes API (/v2/updates/price/latest) returns item.id without the 0x prefix (e.g. "e62df6c8..."). As confirmed by existing examples in this repo (price_feeds/evm/oracle_swap/app/src/App.tsx:26), Pyth price feed IDs are stored/returned without the prefix. The comparison FEEDS.find(f => f.hex === item.id) on line 39 therefore always returns undefined, causing the spread ...asset to contribute no properties. The resulting data objects will be missing symbol, hex, and network — breaking the ScreenerTable display (which keys on row.symbol) and all downstream components that reference symbol.
| { hex: "0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43", symbol: 'BTC', network: 'Bitcoin' }, | |
| { hex: "0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace", symbol: 'ETH', network: 'Ethereum' }, | |
| { hex: "0x2a01deaec9e51a579277b34b122399984d0bbf57e2458a7e42fecd2829867a0d", symbol: 'ADA', network: 'Cardano' } | |
| { hex: "e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43", symbol: 'BTC', network: 'Bitcoin' }, | |
| { hex: "ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace", symbol: 'ETH', network: 'Ethereum' }, | |
| { hex: "2a01deaec9e51a579277b34b122399984d0bbf57e2458a7e42fecd2829867a0d", symbol: 'ADA', network: 'Cardano' } |
Was this helpful? React with 👍 or 👎 to provide feedback.
| AcceptAgreement buyer -> | ||
| traceIfFalse "NOT_BUYER" (isSigned buyer info) && |
There was a problem hiding this comment.
🔴 AcceptAgreement validator uses untrusted redeemer-supplied buyer instead of datum's buyer
The AcceptAgreement case at line 252-253 checks isSigned buyer info where buyer comes from the redeemer (user-supplied data). Any user can supply their own PubKeyHash as the buyer field in the redeemer, sign the transaction, and pass this check — even if they are not the designated buyer in the datum. This contrasts with the DepositFunds case at SmartSupplyLedger.hs:261 which correctly uses ssdBuyer dat from the on-chain datum. The fix should be: isSigned (ssdBuyer dat) info instead of isSigned buyer info.
| AcceptAgreement buyer -> | |
| traceIfFalse "NOT_BUYER" (isSigned buyer info) && | |
| AcceptAgreement buyer -> | |
| traceIfFalse "NOT_BUYER" (isSigned (ssdBuyer dat) info) && |
Was this helpful? React with 👍 or 👎 to provide feedback.
| const validator = { | ||
| type: "PlutusV2", | ||
| script: validatorEntry.compiledCode, | ||
| }; |
There was a problem hiding this comment.
🔴 Plutus version mismatch: Aiken compiles PlutusV3 but JS code creates PlutusV2 validator
The Aiken blueprint at src/assets/plutus.json:4 declares "plutusVersion": "v3", but both CardanoService.js:38 and SmartSupplyPanel.jsx:59 construct the validator with type: "PlutusV2". In Lucid, the type field determines how the script hash is computed — a PlutusV2 hash differs from a PlutusV3 hash for the same compiled code. This mismatch causes the computed scriptAddress to differ from the actual on-chain script address, meaning any transaction built with this validator will target the wrong address and fail.
| const validator = { | |
| type: "PlutusV2", | |
| script: validatorEntry.compiledCode, | |
| }; | |
| const validator = { | |
| type: "PlutusV3", | |
| script: validatorEntry.compiledCode, | |
| }; |
Was this helpful? React with 👍 or 👎 to provide feedback.
| const validator = { | ||
| type: "PlutusV2", | ||
| script: validatorEntry.compiledCode, | ||
| }; |
There was a problem hiding this comment.
🔴 Plutus version mismatch in CardanoService.js: PlutusV2 instead of PlutusV3
Same issue as in SmartSupplyPanel.jsx — CardanoService.js:38 uses type: "PlutusV2" but the Aiken contract in src/assets/plutus.json:4 is compiled as PlutusV3. This will produce an incorrect script hash and address, causing all transactions to fail.
| const validator = { | |
| type: "PlutusV2", | |
| script: validatorEntry.compiledCode, | |
| }; | |
| const validator = { | |
| type: "PlutusV3", | |
| script: validatorEntry.compiledCode, | |
| }; |
Was this helpful? React with 👍 or 👎 to provide feedback.
| const lib = await Lucid.new( | ||
| new Blockfrost( | ||
| "https://cardano-preprod.blockfrost.io/api/v0", | ||
| "preprodW9VepmQEx3r9LPr3QncreNvkBDApZD8m" |
There was a problem hiding this comment.
🔴 Hardcoded Blockfrost API key committed to source control
The Blockfrost project API key "preprodW9VepmQEx3r9LPr3QncreNvkBDApZD8m" is hardcoded directly in the source at line 22. This key will be visible in the public repository, allowing anyone to consume the project's Blockfrost rate limits or potentially abuse it. The .gitignore already excludes .env files, suggesting the intent was to use environment variables. The key should be loaded from import.meta.env.VITE_BLOCKFROST_KEY or similar.
Was this helpful? React with 👍 or 👎 to provide feedback.
| pythPrice: price, | ||
| confidence: Number(item.price.conf) * Math.pow(10, item.price.expo), | ||
| extPrice: price * 1.0002, | ||
| gap: (Math.random() * 0.05), // Variación pequeña para visualización |
There was a problem hiding this comment.
🟡 Arbitrage gap is always a positive random value, making BEARISH regime impossible
At line 46, gap is computed as Math.random() * 0.05, which always produces a value in [0, 0.05). This means the gap field is never negative. Downstream in Screener.jsx:24, the regime classification asset.gap < -0.05 ? 'BEARISH' : 'LATERAL' can never evaluate to 'BEARISH' since gap is never negative. Furthermore, since the max value of Math.random() * 0.05 is just under 0.05, asset.gap > 0.05 is also (almost) never true, so 'BULLISH' is nearly impossible too — all assets will always show as 'LATERAL'.
| gap: (Math.random() * 0.05), // Variación pequeña para visualización | |
| gap: (Math.random() - 0.5) * 0.2, // Variación pequeña para visualización |
Was this helpful? React with 👍 or 👎 to provide feedback.
Pyth Examples Contribution
Type of Contribution
Project Information
Project/Example Name:
Pyth Product Used:
Blockchain/Platform:
Description
What does this contribution do?
How does it integrate with Pyth?
What problem does it solve or demonstrate?
Directory Structure (for new examples)
Testing & Verification
How to Test This Contribution
Prerequisites
Setup & Run Instructions
Deployment Information (if applicable)
Network:
Contract Address(es):
Demo URL:
Checklist
Code Quality
Testing
Additional Context
Related Issues
Fixes #
Screenshots/Demo (if applicable)
Notes for Reviewers
Thank you for contributing to Pyth Examples!