Skip to content

Commit eccf88f

Browse files
committed
2 parents 9d2cfad + f29f808 commit eccf88f

38 files changed

Lines changed: 18255 additions & 1 deletion

.vscode/settings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"snyk.advanced.autoSelectOrganization": true
3+
}

README.md

Lines changed: 229 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,229 @@
1-
🚀 Pyth Cardano Hackathon 2026Team: Los Magníficos!Agustin Salinas (@AgustinBadi)Mauricio Navarrete (@lordkhyron)Rodrigo Oyarzun (@Rodrigoioyz)Contact: librenotgratis@tuta.io📋 Contribution InformationCategoryDetailsContribution Type✅ Hackathon SubmissionProject NameExample SubmissionPyth Product🟢 Pyth Price FeedsBlockchain₳ Cardano📝 Description(Empty)🛠️ Quick Start Guide(Empty)✅ Quality Checklist[x] Make it beautiful: Clean hierarchy and formatting.[x] Code Standards: Follows existing repository patterns.[x] Security: No hardcoded values; uses environment variables.[x] Verification: Locally tested and verified.
1+
🚀 Pyth Cardano Hackathon 2026
2+
3+
Team: Los Magníficos!
4+
Agustin Salinas (@AgustinBadi)
5+
Mauricio Navarrete (@lordkhyron)
6+
Rodrigo Oyarzun (@Rodrigoioyz)
7+
Contact: librenotgratis@tuta.io
8+
9+
📋 Contribution Information
10+
11+
| Category | Details |
12+
|---|---|
13+
| Contribution Type | ✅ Hackathon Submission |
14+
| Project Name | Synth Peso |
15+
| Pyth Product | 🟢 Pyth Price Feeds (Pyth Lazer) |
16+
| Blockchain | ₳ Cardano |
17+
18+
---
19+
20+
## 📝 What is Synth Peso?
21+
22+
**Synth Peso** is a synthetic ADA/USD stablecoin protocol built on Cardano. Users lock ADA as collateral and mint synth tokens pegged to the USD value of that ADA, as determined in real-time by the **Pyth Lazer oracle**. Burning synth tokens returns the corresponding ADA from the collateral pool.
23+
24+
The protocol enforces:
25+
- **Overcollateralization** — you can only mint a fraction of your ADA's USD value (controlled by `collateral_ratio`)
26+
- **Health checks on withdrawal** — you cannot burn synth and withdraw ADA if it leaves the position below the liquidation threshold
27+
- **Open liquidation** — anyone can liquidate an undercollateralized position
28+
- **Owner-only burns** — only the position owner (verified via signature) can voluntarily burn and withdraw
29+
30+
---
31+
32+
## ⚙️ How It Works
33+
34+
### Mint (ADA → Synth USD)
35+
36+
1. User sends ADA to the pool UTxO
37+
2. The on-chain validator reads the live ADA/USD price from Pyth Lazer
38+
3. It computes: `synth_to_mint = (ada_deposited × collateral_ratio / 100) × price`
39+
4. The minting policy mints exactly that amount of synth tokens to the user
40+
41+
### Burn (Synth USD → ADA)
42+
43+
1. User specifies how much ADA to withdraw from the pool
44+
2. Validator reads live oracle price
45+
3. Computes synth to burn: `synth_burned = ada_withdrawn × raw_price / 10^abs_exp`
46+
4. Checks remaining position health: `health = (remaining_ada × raw_price / 10^abs_exp) / remaining_debt ≥ liquidation_threshold`
47+
5. Verifies the transaction is signed by the position owner
48+
6. ADA is released from the pool
49+
50+
### Liquidate
51+
52+
1. Any user can trigger liquidation on an undercollateralized position (`health < liquidation_threshold`)
53+
2. The liquidator burns synth tokens and receives the corresponding ADA from the pool
54+
3. No owner signature required — the position's health condition is the only gate
55+
56+
---
57+
58+
## 🔮 How Pyth Lazer is Used
59+
60+
The contract uses [`pyth-network/pyth-lazer-cardano`](https://github.com/pyth-network/pyth-lazer-cardano) (pinned at commit `f78b676`).
61+
62+
### On-chain price reading
63+
64+
```aiken
65+
let updates = pyth.get_updates(pyth_policy_id, tx)
66+
expect [update] = updates
67+
expect Some(feed) = list.find(feeds, fn(f) { u32.as_int(f.feed_id) == ada_usd_feed_id })
68+
expect Some(Some(raw_price)) = feed.price
69+
expect Some(exponent) = feed.exponent
70+
// real_price = raw_price × 10^exponent
71+
```
72+
73+
### How the price reaches the contract
74+
75+
Every mint/burn/liquidate transaction must include:
76+
77+
1. **Pyth State NFT** as a reference input (identified by `pyth_policy_id`) — never spent
78+
2. **A 0-ADA withdrawal** from the Pyth verify script, carrying the signed price message as the redeemer
79+
80+
The Pyth verify script validates the **Ed25519 signature** on each price message before the main validator runs. By the time `get_updates` is called, the price is already cryptographically authenticated.
81+
82+
### Price feed
83+
84+
- **Asset:** ADA/USD
85+
- **Feed ID:** 16
86+
- **Exponent:** -8 (i.e. `raw_price = 70_000_000``$0.70 per ADA`)
87+
- **No contention:** The Pyth State NFT is a reference input — multiple users can mint/burn in the same block without UTxO conflicts
88+
89+
---
90+
91+
## 📐 Protocol Parameters
92+
93+
These values are set at deployment time and enforced entirely on-chain:
94+
95+
| Parameter | Value | Description |
96+
|---|---|---|
97+
| `collateral_ratio` | **150%** | You can mint at most 66% of your ADA's USD value in synth tokens |
98+
| `liquidation_threshold` | **120%** | Positions below this health ratio can be liquidated by anyone |
99+
| `ada_usd_feed_id` | **16** | Pyth Lazer feed ID for ADA/USD |
100+
101+
**Example:** Depositing 100 ADA at $0.70/ADA ($70 collateral value) → you can mint up to **$46.67 of synth-USD**. If ADA drops to $0.56, your health ratio hits 120% and the position becomes liquidatable.
102+
103+
---
104+
105+
## 👤 User Flow
106+
107+
### Minting synth-USD
108+
1. User sends ADA to the protocol pool UTxO
109+
2. On-chain validator fetches live ADA/USD price from Pyth Lazer
110+
3. Calculates max synth: `synth = ada × price × (100 / collateral_ratio)`
111+
4. Minting policy issues exactly that amount of synth tokens to the user's wallet
112+
113+
### Burning synth-USD (withdraw ADA)
114+
1. User decides how much ADA to withdraw
115+
2. Validator fetches live price from Pyth Lazer
116+
3. Calculates synth to burn: `synth_burned = ada_withdrawn × price`
117+
4. Verifies remaining position stays above 120% health
118+
5. User signs the transaction — synth is burned, ADA returned
119+
120+
### Liquidation (undercollateralized position)
121+
1. ADA price drops → a position's health falls below 120%
122+
2. Any user can call `Liquidate`
123+
3. Liquidator burns synth tokens, receives the equivalent ADA from the pool
124+
4. No owner signature required — the health condition is the only gate
125+
126+
---
127+
128+
## 🛡️ Quality Assurance & Reliability
129+
130+
### Edge cases handled on-chain
131+
- **Zero deposit/withdrawal blocked:** `ada_deposited >= 1` and `ada_withdrawn >= 1` enforced explicitly
132+
- **Zero debt guard:** `health_ratio` fails immediately if `debt_amount == 0` — prevents division by zero
133+
- **Double Option price unwrap:** Pyth feed returns `Option<Option<Int>>` — the validator explicitly handles `None` (field missing) and `Some(None)` (price unavailable), failing both cases
134+
- **Single update enforced:** `expect [update] = updates` — rejects transactions with zero or multiple price messages
135+
136+
### Oracle failure handling
137+
- If the Pyth withdraw script is not included in the transaction, `pyth.get_updates` returns an empty list and the validator fails — **no stale or missing price is ever accepted**
138+
- The Ed25519 signature on each price message is verified by the Pyth verify script before our validator runs — invalid or replayed messages are rejected at the protocol level
139+
140+
### Price anomaly protection
141+
- Price is read fresh from the oracle in every transaction — there is no cached or stored price in the datum
142+
- The `collateral_ratio` and `liquidation_threshold` parameters provide a safety buffer against sudden price moves
143+
144+
---
145+
146+
## 💼 Business Development & Viability
147+
148+
### Target users
149+
- ADA holders who want USD-denominated liquidity without selling their ADA
150+
- DeFi users on Cardano seeking synthetic exposure to USD
151+
- Protocols that need a decentralized, oracle-backed stablecoin primitive
152+
153+
### Market need
154+
Cardano has existing decentralized stablecoins (DJED by COTI, iUSD by Indigo Protocol). Synth Peso **expands the offering** with a lightweight, single-collateral design that uses Pyth Lazer — a battle-tested, high-frequency oracle — rather than a custom price mechanism. This brings institutional-grade price feeds to Cardano CDP protocols.
155+
156+
### Competitive positioning
157+
158+
| Protocol | Oracle | Collateral | Chain |
159+
|---|---|---|---|
160+
| DJED (COTI) | Custom | ADA | Cardano |
161+
| iUSD (Indigo) | Chainlink | ADA | Cardano |
162+
| MakerDAO (DAI) | Chainlink | ETH/multi | Ethereum |
163+
| **Synth Peso** | **Pyth Lazer** | **ADA** | **Cardano** |
164+
165+
Pyth Lazer offers sub-second price updates and is already used across 50+ chains — giving Synth Peso a credibility advantage at launch.
166+
167+
### Revenue model
168+
Protocol fees collected on mint and liquidation events (configurable via protocol parameters). Fee revenue funds ongoing development and can be directed to a DAO treasury as the protocol matures.
169+
170+
### Scalability
171+
- **No UTxO contention:** The Pyth State NFT is a reference input — any number of users can mint or burn in the same block without competing for the same UTxO
172+
- **Permissionless liquidation:** Anyone can liquidate, eliminating the need for a centralized keeper network
173+
- **Pyth partnership potential:** As Pyth expands its Cardano presence, Synth Peso is positioned to add new synthetic assets (BTC/USD, ETH/USD) by simply deploying new validator instances with different feed IDs
174+
175+
---
176+
177+
## 🛠️ How to Build
178+
179+
### Prerequisites
180+
181+
- [Aiken](https://aiken-lang.org) v1.1.19
182+
183+
```bash
184+
aikup install v1.1.19
185+
```
186+
187+
### Build
188+
189+
```bash
190+
cd on-chain
191+
aiken build
192+
```
193+
194+
This compiles the contracts and generates `on-chain/plutus.json` (the Plutus blueprint).
195+
196+
### Run tests
197+
198+
```bash
199+
cd on-chain
200+
aiken check
201+
```
202+
203+
All 25 unit tests in `lib/utils.ak` cover:
204+
- `health_ratio` — collateral/debt ratio calculation
205+
- `can_adjust` / `is_liquidatable` — position health gates
206+
- `liquidator_payout` / `protocol_payout` — ADA distribution on liquidation
207+
- `compute_expected_synth_amount` — ADA → synth USD conversion (mint and burn directions)
208+
209+
### Project structure
210+
211+
```
212+
on-chain/
213+
validators/
214+
synth-dolar.ak # Main validator: mint policy + spend guard
215+
lib/
216+
utils.ak # Math helpers + 25 unit tests
217+
types/
218+
cdp.ak # CdpDatum type
219+
aiken.toml # Dependencies
220+
```
221+
222+
---
223+
224+
✅ Quality Checklist
225+
226+
- [x] Make it beautiful: Clean hierarchy and formatting.
227+
- [x] Code Standards: Follows existing repository patterns.
228+
- [x] Security: No hardcoded values; uses environment variables.
229+
- [x] Verification: Locally tested and verified.

backend/.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
node_modules
2+
.env
3+
dist
4+
npm-debug.log
5+
.DS_Store

backend/app.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import dotenv from 'dotenv';
2+
import Server from './models/server';
3+
dotenv.config();
4+
const server = new Server();
5+
server.listen();

0 commit comments

Comments
 (0)