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>
214 lines
11 KiB
Text
214 lines
11 KiB
Text
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.
|
||
}
|
||
}
|