deviant/contracts/DeviantReflectiveDRA.cash
Local Dev 631541c98c docs(reorg): regroup native-ASM specs under ASM_Native + move Pari_P2P into Betting
Four moves (git mv, history preserved on all 39 files):
- ASM_Potidaea_OrbitalSwap -> ASM_Native/Potidaea_OrbitalSwap  (renamed, dropped the ASM_ prefix; now nested under ASM_Native)
- MBA_Shares               -> ASM_Native/MBA_Shares
- FIATm                    -> ASM_Native/FIATm
- Pari_P2P                 -> Betting/Pari_P2P

ASM_Native now groups the native-BCH swap (Potidaea) with the native asset families it swaps (FIATμ/BCHm, MBA/shares). Rewrote ASM_Native/README.md from a pointer stub into a real folder index describing the contained subfolders + how they fit (mechanism vs assets).

Rewrote every reference: Potidaea internal links (depth +1; self-folder refs collapsed), external links from DEX_Anthemus/wiki/ASM_CrossChain, prose/path refs across Parameters + wiki + CLAUDE.md + docs + code-comment doc-pointers (scripts/src/contracts), memory, and .gitignore (transcripts ignore rule). Co-moved siblings (FIATm<->MBA_Shares) kept their ../sibling links untouched since they stayed siblings under ASM_Native.

Verified with a link-resolver: all 453 relative links across 165 files resolve.
Snapshots keep old paths (historical changelog). Parallel FX-desk/uniform-reserve track left untouched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-19 17:09:40 +02:00

214 lines
11 KiB
Text
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

pragma cashscript ^0.12.0;
// DeviantReflectiveDRA — shared-pool reflective Dynamic Rate Asset.
//
// Sibling of DeviantExpDRA / StepDRA / SuperExpDRA (per-unit bonding-curve
// variants). This DRA variant is structurally distinct:
// - SHARED POOL: all BCH lives in one covenant; DRA tokens are pro-rata
// claims on the pool, NOT self-backed per-unit locks.
// - REFLECTIVE RATE: mint price moves inversely to an external EUR oracle
// rate, asymmetrically dampened by adoption catalysts.
// - FEE RECEIVER: external FIATm covenants route a slice of their tx fees
// into the pool, lifting NAV per DRA for ALL holders monotonically.
//
// Design record: Parameters/ASM_Native/FIATm/dra_dynamic-rate-asset_FOR-design-record.md
// Status: chipnet-stage covenant sketch. NOT production-ready. Simulator
// validation in scripts/sim-dra-controller.mjs must confirm the asymmetric
// three-force model converges to its maturity envelope before this is
// promoted to chipnet genesis.
//
// State packed in the NFT commitment (the persistent controller UTXO):
// bytes 8: supply (uint64 — DRA units outstanding)
// bytes 4: catalysts (uint32 — adoption counter)
// bytes 8: dra_rate_0 (uint64 — genesis DRA sats-per-unit, immutable)
// bytes 8: eur_rate_0 (uint64 — genesis EUR sats-per-unit, immutable)
//
// Layout: supply || catalysts || dra_rate_0 || eur_rate_0 = 28 bytes total.
//
// The covenant's `value` field IS the pool BCH balance — no separate accounting.
// NAV per DRA at any moment = covenant.value / supply.
contract DeviantReflectiveDRA(
bytes tokenCategory, // DRA token category
pubkey oraclePubKey, // EUR oracle public key
int catalystTrigger, // cumulative mints per catalyst (210,000 per §12a.2)
int beta_x1000, // β × 1000 (e.g. 100 = 0.100; counter strength per catalyst)
int gamma_x1000 // γ × 1000 (e.g. 50 = 0.050; gain acceleration per catalyst)
) {
// ──────────────────────────────────────────────────────────────────
// mint(oracleMessage, oracleSignature, n_dra, recipient)
//
// Caller provides:
// - oracle message containing current EUR_rate (sats per EURm)
// - oracle signature over that message
// - n_dra: integer DRA units to mint
// - recipient locking bytecode
//
// Caller's BCH input = covenant pool top-up.
// The covenant computes the reflective DRA_rate from the oracle EUR_rate,
// verifies the input BCH equals n_dra × DRA_rate, mints n_dra DRA tokens
// to the recipient, advances supply + catalyst counters.
//
// tx layout:
// inputs[0] = the controller UTXO (this contract)
// inputs[1] = caller funding input (P2PKH)
// outputs[0] = controller UTXO recreated with updated commitment + pool
// outputs[1] = n_dra DRA tokens to recipient
// outputs[2] = caller's change (optional)
// ──────────────────────────────────────────────────────────────────
function mint(
bytes oracleMessage,
datasig oracleSignature,
int n_dra,
bytes recipientLockingBytecode
) {
require(n_dra > 0);
require(checkDataSig(oracleSignature, oracleMessage, oraclePubKey));
// Parse oracle message: assumes format [4-byte timestamp][8-byte eur_rate]
// (Real oracle stack §14 layered checks are layered OUTSIDE this covenant.)
int eur_rate = int(oracleMessage.split(4)[1].split(8)[0]);
require(eur_rate > 0);
// Unpack current state from NFT commitment
bytes state = tx.inputs[this.activeInputIndex].nftCommitment;
int supply = int(state.split(8)[0]);
int catalysts = int(state.split(8)[1].split(4)[0]);
int dra_rate_0 = int(state.split(12)[1].split(8)[0]);
int eur_rate_0 = int(state.split(20)[1].split(8)[0]);
// Compute reflective DRA_rate — doubly asymmetric (counter / gain).
//
// r_x1000 = eur_rate * 1000 / eur_rate_0
// delta = eur_rate - eur_rate_0
//
// if r_x1000 > 1000 (EUR strengthens — negative side, dampened):
// counter_x1000 = r_x1000 * (1000 + catalysts * beta_x1000) / 1000
// dra_rate_raw = dra_rate_0 - (delta * 1000 / counter_x1000)
// else (EUR weakens — positive side, amplified by gain):
// gain_x1000 = 1000 + catalysts * gamma_x1000
// dra_rate_raw = dra_rate_0 - (delta * gain_x1000 / 1000)
int r_x1000 = eur_rate * 1000 / eur_rate_0;
int delta = eur_rate - eur_rate_0;
int dra_rate = dra_rate_0;
if (r_x1000 > 1000) {
int counter_x1000 = r_x1000 * (1000 + catalysts * beta_x1000) / 1000;
dra_rate = dra_rate_0 - (delta * 1000 / counter_x1000);
} else {
int gain_x1000 = 1000 + catalysts * gamma_x1000;
dra_rate = dra_rate_0 - (delta * gain_x1000 / 1000);
}
// Amplitude clamp — widens with adoption (NOT tightens), asymmetric
int lower_x1000 = 500 - catalysts * 15;
if (lower_x1000 < 50) { lower_x1000 = 50; }
int upper_x1000 = 2000 + catalysts * 100;
int min_rate = dra_rate_0 * lower_x1000 / 1000;
int max_rate = dra_rate_0 * upper_x1000 / 1000;
if (dra_rate < min_rate) { dra_rate = min_rate; }
if (dra_rate > max_rate) { dra_rate = max_rate; }
require(dra_rate > 0);
// Mint price = max(reflective DRA_rate, current NAV per DRA).
//
// The max-of-two is structural: new mints cannot enter below NAV (no
// dilution), and during EUR-weakness events post-catalyst the gain-
// amplified reflective rate exceeds NAV → new mints pay a PREMIUM that
// lifts NAV for all holders. This is the structural channel by which
// the gain function accretes value to per-DRA NAV over the adoption arc.
int current_pool = tx.inputs[this.activeInputIndex].value;
int nav_per_dra = dra_rate_0;
if (supply > 0) { nav_per_dra = current_pool / supply; }
int mint_price = nav_per_dra;
if (dra_rate > nav_per_dra) { mint_price = dra_rate; }
require(mint_price > 0);
// Required BCH input from caller
int sats_in = n_dra * mint_price;
require(sats_in > 0);
// New state — catalysts hard-capped at 30 (asymptote, design §6)
int new_supply = supply + n_dra;
int new_catalysts = new_supply / catalystTrigger;
if (new_catalysts > 30) { new_catalysts = 30; }
bytes new_state = bytes8(new_supply) + bytes4(new_catalysts) + bytes8(dra_rate_0) + bytes8(eur_rate_0);
// outputs[0] = controller recreated
require(tx.outputs[0].lockingBytecode == tx.inputs[this.activeInputIndex].lockingBytecode);
require(tx.outputs[0].tokenCategory == tx.inputs[this.activeInputIndex].tokenCategory);
require(tx.outputs[0].nftCommitment == new_state);
require(tx.outputs[0].value == tx.inputs[this.activeInputIndex].value + sats_in);
// outputs[1] = n_dra DRA tokens to recipient
require(tx.outputs[1].lockingBytecode == recipientLockingBytecode);
require(tx.outputs[1].tokenCategory == tokenCategory);
require(tx.outputs[1].tokenAmount == n_dra);
require(tx.outputs[1].value >= 546);
}
// ──────────────────────────────────────────────────────────────────
// redeem(n_dra, recipient)
//
// Caller burns n_dra DRA tokens; covenant releases pro-rata pool BCH:
// sats_out = covenant.value × n_dra / supply
//
// tx layout:
// inputs[0] = the controller UTXO
// inputs[1] = caller's DRA tokens to burn
// outputs[0] = controller UTXO recreated (reduced supply + pool)
// outputs[1] = sats_out to recipient (no DRA tokens)
// ──────────────────────────────────────────────────────────────────
function redeem(int n_dra, bytes recipientLockingBytecode) {
require(n_dra > 0);
// Verify input[1] carries the right DRA tokens being burned
require(tx.inputs[1].tokenCategory == tokenCategory);
require(tx.inputs[1].tokenAmount == n_dra);
// Unpack state
bytes state = tx.inputs[this.activeInputIndex].nftCommitment;
int supply = int(state.split(8)[0]);
int catalysts = int(state.split(8)[1].split(4)[0]);
int dra_rate_0 = int(state.split(12)[1].split(8)[0]);
int eur_rate_0 = int(state.split(20)[1].split(8)[0]);
require(supply >= n_dra);
int sats_out = tx.inputs[this.activeInputIndex].value * n_dra / supply;
require(sats_out > 0);
int new_supply = supply - n_dra;
bytes new_state = bytes8(new_supply) + bytes4(catalysts) + bytes8(dra_rate_0) + bytes8(eur_rate_0);
// outputs[0] = controller recreated (catalyst count NEVER decreases — adoption is monotonic)
require(tx.outputs[0].lockingBytecode == tx.inputs[this.activeInputIndex].lockingBytecode);
require(tx.outputs[0].tokenCategory == tx.inputs[this.activeInputIndex].tokenCategory);
require(tx.outputs[0].nftCommitment == new_state);
require(tx.outputs[0].value == tx.inputs[this.activeInputIndex].value - sats_out);
// outputs[1] = pure BCH to recipient (DRA was burned by absence in outputs)
require(tx.outputs[1].lockingBytecode == recipientLockingBytecode);
require(tx.outputs[1].value == sats_out);
// tokenCategory absence enforced by CashScript output validation
}
// ──────────────────────────────────────────────────────────────────
// receiveFees() — permissive deposit; no DRA minted, no state change
// except pool growth.
//
// Anyone can call this. The FIATm-family fee-redirector contracts call
// it as part of their mint/redeem/swap operations to route fees here.
//
// tx layout:
// inputs[0] = controller UTXO
// inputs[1+] = fee-paying inputs
// outputs[0] = controller UTXO recreated with pool grown
// ──────────────────────────────────────────────────────────────────
function receiveFees() {
// outputs[0] = controller recreated, same commitment, pool grown
require(tx.outputs[0].lockingBytecode == tx.inputs[this.activeInputIndex].lockingBytecode);
require(tx.outputs[0].tokenCategory == tx.inputs[this.activeInputIndex].tokenCategory);
require(tx.outputs[0].nftCommitment == tx.inputs[this.activeInputIndex].nftCommitment);
require(tx.outputs[0].value > tx.inputs[this.activeInputIndex].value);
// Pool MUST grow — refusing zero or negative deposits.
}
}