deviant/contracts/DistributionVault.cash
walerikus 518a3ce174 chore: initial project baseline — full Deviant codebase under version control
Brings the whole project into git (previously only the on-ramp feature and
a few parallel files were tracked). Includes: wallet core (src/), CashScript
contracts/, the Capacitor shell (shells/), scripts/, tests, and the docs
corpus (wiki/, snapshots/, Parameters/, Archive/, KnowledgeBase text).

Excluded via .gitignore: node_modules/, dist/, .env (secrets), testnet WIF
key files (.chipnet-*.json, devWallets.ts), KnowledgeBase/RAW media (~9.6 GB),
transcripts/ (session logs), and machine-local config (.claude/*.local,
*.lock). Secret-scanned before commit — no credentials in the tree.

Note: src/swapMath.ts, src/swapBuilder.ts, contracts/OpenMintToken.cash are
legacy (OP_RETURN era) but still imported; committed as-is, flagged for a
separate removal once de-referenced.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 20:38:07 +02:00

61 lines
2.9 KiB
Text

pragma cashscript ^0.12.0;
// DistributionVault — ADR-0042 payout side.
//
// Holds the accrued shareholder profit-share pool. Pays each holder their
// oracle-attested entitlement; the company cannot take or redirect it — the
// only valid spend pays an oracle-named recipient an oracle-named amount and
// returns the remainder to this same vault.
//
// Replay-soundness: the oracle signature is bound to THIS vault UTXO's outpoint
// (txhash+index). Spending the UTXO consumes that outpoint and produces a new
// vault UTXO with a different outpoint, so a signature can be used at most once.
// Payouts are therefore sequential — one recipient per tx, each consuming the
// current vault UTXO and re-emitting the decremented pool.
//
// oracleMessage layout (69 bytes):
// recipientLockingBytecode(25) ‖ amount(8 LE) ‖ outpointTxHash(32) ‖ outpointIndex(4 LE)
//
// Output layout (payout):
// [0] recipient gets `amount` (pure BCH)
// [1] remainder back to this vault: value == vaultInput.value - amount
// [2+] miner-fee funding change (external input + change, unconstrained)
//
// Double-claim across recipients is the oracle's off-chain bookkeeping
// (it won't attest the same holder twice per epoch), bounded by the pool:
// the vault can never pay out more BCH than it holds.
contract DistributionVault(pubkey oraclePk) {
function payout(bytes recipientLockingBytecode, datasig oracleSig, bytes oracleMessage) {
require(checkDataSig(oracleSig, oracleMessage, oraclePk));
require(oracleMessage.length == 69);
// parse: recipient(25) ‖ amount(8) ‖ opTx(32) ‖ opIdx(4)
bytes lb, bytes r1 = oracleMessage.split(25);
bytes amtBytes, bytes r2 = r1.split(8);
bytes opTx, bytes opIdxBytes = r2.split(32);
require(lb == recipientLockingBytecode);
// bind this signature to THIS vault UTXO — prevents replay.
require(opTx == tx.inputs[this.activeInputIndex].outpointTransactionHash);
require(int(opIdxBytes) == tx.inputs[this.activeInputIndex].outpointIndex);
int amount = int(amtBytes);
require(amount >= 546);
// [0] pay the oracle-named recipient exactly the oracle-named amount.
require(tx.outputs[0].lockingBytecode == recipientLockingBytecode);
require(tx.outputs[0].value == amount);
require(tx.outputs[0].tokenCategory == 0x);
// [1] remainder back to this same vault — pool decrements by exactly `amount`.
// (Miner fee is funded by an external input + change at [2+], so the vault
// accounting stays exact; the company never touches this stream.)
int remainder = tx.inputs[this.activeInputIndex].value - amount;
require(remainder >= 546);
require(tx.outputs[1].lockingBytecode == tx.inputs[this.activeInputIndex].lockingBytecode);
require(tx.outputs[1].value == remainder);
require(tx.outputs[1].tokenCategory == 0x);
}
}