Skip to content

Commit 9f4ca71

Browse files
committed
wip #3
1 parent efea417 commit 9f4ca71

3 files changed

Lines changed: 113 additions & 4 deletions

File tree

CLAUDE.md

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,3 +163,109 @@ synth_micro = ada_lovelaces × raw_price / 10^8
163163

164164
### Plutus version
165165
Plutus v3 — use `ScriptContext` patterns accordingly.
166+
167+
## Frontend (TypeScript / MeshSDK)
168+
169+
Located in `frontend/src/tx/`. Uses MeshSDK v1.9.0-beta + Blockfrost as provider (preprod).
170+
171+
### Key files
172+
173+
| File | Purpose |
174+
|---|---|
175+
| `contract.ts` | All shared constants: script CBOR, protocol params, Pyth addresses, amount helpers |
176+
| `mint.ts` | `buildMintTx` — deposit ADA, mint synth tokens |
177+
| `burn.ts` | `buildBurnTx` — burn synth tokens, reclaim ADA |
178+
| `liquidate.ts` | `buildLiquidateTx` — permissionless liquidation of undercollateralised positions |
179+
180+
### Important: script CBOR encoding
181+
182+
Aiken's `plutus.json` outputs `compiledCode` in **single-CBOR** encoding. MeshSDK's `applyParamsToScript` requires **double-CBOR** encoding. Always wrap with `applyCborEncoding` before passing to `applyParamsToScript`:
183+
184+
```typescript
185+
const UNPARAMETERISED_SCRIPT_CBOR = applyCborEncoding(RAW_COMPILED_CODE);
186+
```
187+
188+
This is already done in `contract.ts` — do not remove it.
189+
190+
### Script address derivation
191+
192+
```typescript
193+
const scriptCbor = applyParamsToScript(UNPARAMETERISED_SCRIPT_CBOR, [
194+
PARAMS.PYTH_POLICY_ID,
195+
PARAMS.ADA_USD_FEED_ID,
196+
PARAMS.COLLATERAL_RATIO,
197+
PARAMS.LIQUIDATION_THRESHOLD,
198+
]);
199+
const poolAddress = serializePlutusScript({ code: scriptCbor, version: "V3" }, undefined, 0).address;
200+
const scriptHash = resolvePlutusScriptHash(poolAddress); // also the minting policy ID
201+
```
202+
203+
Known derived values (preprod):
204+
- `poolAddress``addr_test1wq8lshhawfkay7fc68078h7hg36mgnqpfnn82a7y4g067cs78y0m9`
205+
- `scriptHash``0ff85efd726dd27938d1dfe3dfd74475b44c014ce67577c4aa1faf62`
206+
207+
### Known preprod constants (`contract.ts`)
208+
209+
```typescript
210+
PARAMS.PYTH_POLICY_ID = "d799d287105dea9377cdf9ea8502a83d2b9eb2d2050a8aea800a21e6"
211+
PARAMS.ADA_USD_FEED_ID = 16
212+
PARAMS.COLLATERAL_RATIO = 150
213+
PARAMS.LIQUIDATION_THRESHOLD = 120
214+
215+
PYTH.STATE_ADDRESS = "addr_test1wrm3tr5zpw9k2nefjtsz66wfzn6flnphr5kd6ak9ufrl3wcqqfyn8"
216+
PYTH.STATE_ASSET_NAME = "50797468205374617465" // hex("Pyth State")
217+
// Asset fingerprint: asset1kjr4k3m0xe5c747n6yv2s9dlfhkmzgceqs82jy (verified via CIP-14)
218+
219+
PYTH.WITHDRAW_SCRIPT_CBOR = "TODO" // Pyth verify script — get from Pyth team
220+
PYTH.WITHDRAW_ADDRESS = "TODO" // reward address of the verify script
221+
```
222+
223+
### Mesh "Data" format for redeemers/datums
224+
225+
In MeshSDK's "Mesh" encoding (used with `"Mesh"` flag on builder calls):
226+
- `ByteArray` → plain hex string
227+
- `List<T>` → JS array `[...]`
228+
- `Constr(N, fields)``mConStr0([...])` / `mConStr1([...])` / `mConStr2([...])` from `@meshsdk/core`
229+
230+
Do **not** use `mBytes` or `mList` — they are not exported by `@meshsdk/core`. Use hex strings and arrays directly.
231+
232+
### Redeemer mapping
233+
234+
| Action | Spend redeemer | Mint redeemer |
235+
|---|---|---|
236+
| Mint | `mConStr0([])` | `mConStr0([])` |
237+
| Burn | `mConStr1([])` | `mConStr1([])` |
238+
| Liquidate | `mConStr2([])` | `mConStr2([])` |
239+
240+
Pyth withdrawal redeemer: `[pythHex]` — a JS array containing the hex-encoded Solana wire format price message returned by the backend as `solanaPayload`.
241+
242+
### Pyth price message (`pythHex` / `solanaPayload`)
243+
244+
The backend (`/price` endpoint) returns `solanaPayload` — a hex string of the Solana wire format signed price message:
245+
246+
```
247+
[4 bytes] magic: b9 01 1a 82
248+
[64 bytes] Ed25519 signature
249+
[32 bytes] public key
250+
[2 bytes] payload length (u16 LE)
251+
[4 bytes] payload magic: 75 d3 c7 93
252+
[8 bytes] timestamp_us (u64 LE)
253+
[1 byte] channel_id
254+
[1 byte] feed count
255+
[4 bytes] feed_id = 16 (ADA/USD, u32 LE)
256+
[...] properties: Price (i64 LE), Exponent (i16 LE), ...
257+
```
258+
259+
This is passed as the withdrawal redeemer to the Pyth verify script, which validates the Ed25519 signature before our validator runs.
260+
261+
### Amount helpers
262+
263+
```typescript
264+
// Synth to mint for a given ADA deposit
265+
computeMintAmount(lovelaces, price) = (lovelaces × rawPrice / 1e8) × 100 / collateralRatio
266+
267+
// ADA to return when burning synth
268+
computeBurnReturn(synthMicro, price) = synthMicro × 1e8 / rawPrice
269+
```
270+
271+
Where `rawPrice = Math.round(price * 1e8)` (price is the float ADA/USD value).

frontend/src/tx/contract.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,16 @@ export const PARAMS = {
3535
export const PYTH = {
3636
// Address where the Pyth State NFT lives (constant — the NFT always returns here).
3737
// Query this at runtime to find the current UTxO holding the NFT.
38-
STATE_ADDRESS: "TODO" as string,
38+
STATE_ADDRESS: "addr_test1wrm3tr5zpw9k2nefjtsz66wfzn6flnphr5kd6ak9ufrl3wcqqfyn8",
3939

4040
// Asset unit = policy_id + hex("Pyth State") used to identify the NFT in the UTxO.
4141
STATE_ASSET_NAME: "50797468205374617465", // "Pyth State" in hex
4242

4343
// The Pyth withdraw script verifies the Ed25519 price signature.
44-
// Its reward address is used for the zero-ADA withdrawal.
45-
WITHDRAW_SCRIPT_CBOR: "TODO" as string,
46-
WITHDRAW_ADDRESS: "TODO" as string, // bech32 reward address on preprod
44+
// Script hash read from Pyth State UTxO inline datum (last field of Constr 0).
45+
WITHDRAW_SCRIPT_HASH: "68a8972304546f254cbf625996c3a9e2ac860f77a9fcd4ee9f73907b",
46+
WITHDRAW_ADDRESS: "stake_test17p5239erq32x7f2vha39n9kr4832eps0w75le48wnaeeq7c4w59zg",
47+
WITHDRAW_SCRIPT_CBOR: "TODO" as string, // CBOR needed — check if deployed as reference script
4748
};
4849

4950
// ── Amount helpers ────────────────────────────────────────────────────────────

frontend/src/tx/mint.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,11 @@ function getScript() {
3535

3636
// Bech32 script address on preprod (network id = 0).
3737
const poolAddress = serializePlutusScript(script, undefined, 0).address;
38+
console.log("[getScript] poolAddress:", poolAddress);
3839

3940
// The policy ID is the Blake2b-224 hash of the parameterised script.
4041
const scriptHash = resolvePlutusScriptHash(poolAddress);
42+
console.log("[getScript] scriptHash (policyId):", scriptHash);
4143

4244
return { scriptCbor, scriptHash, poolAddress };
4345
}

0 commit comments

Comments
 (0)