deviant/scripts/chipnet-mint-pyusd-solana.mjs
Local Dev debd6a6fbb chore: sweep in-flight work across all domains
Snapshot commit rolling up ~255 files of coherent-but-multi-domain in-flight
work that had accumulated on this branch. Split by area:

Contracts + covenants
- New: AsmFxSwap, DeviantOpenMintNBA, DeviantTieredMintOracleFT,
  TermCouponVault, UniformReserve, UniformReserveAggregate.
- Verify-artifact refresh (src/verify/artifacts/*.json + canonical.ts).

Wallet + shell (shells/app + src/wallet)
- App.tsx, MainScreen, ArtemisionScreen, AssetDetail, AgoraScreen,
  SettingsScreen, Unlock, TokenImportModal, UniformFiat/DepositPanel,
  KatalogosPanel (renamed from PinaxPanel), shell.css.
- src/wallet: wallet.ts, runtime.ts, index.ts. Core registry/chipnetFile.
- Deleted stale hook: useAllDevBalances.ts.

Cross-chain + correspondent (services/correspondent + scripts)
- Correspondent server/bch/config updates for PYUSD Solana, EURC Sepolia,
  aggregate reserve flows.
- New scripts: PYUSD roundtrip, EURC onboarding, GMX game loop /
  genesis / mint sanity, tiered mint fee, aggregate reserve, product2
  shares dividends, product3 t-bond, uniform fiat cell tests.

Telegram order-book (P2PExchange bot)
- db.ts, index.ts, en/ru locales — updates upstream from the extracted
  standalone repo at D:/Dev/P2PExchange.

Docs — Parameters (specs), wiki, snapshots, design mockups
- Parameters: FIATm/MBA_Shares/Potidaea/Anthemus refinements +
  ASM_CrossChain/DebitCredit + UniformFiat + Anthemus DEX MVP prompt +
  Artemision + Athenae Politeia + Philosophy + SSHkeyServer runbook +
  new dApp/{Artemision,Katalogos,Pinax,Pari_escrow,SURFACES}.
- wiki: cross-chain, games-tote, glossary, governance/voting-systems,
  infra, wallet, wallet-ui-design, decisions (ADR log).
- snapshots: catch-up entries and INDEX regeneration.
- design: mockups refreshed (agora, asset-detail, assets-tab, potidaea)
  + Potidaea assets + tote deploy notes.

Housekeeping
- .gitignore: exclude the new root test/session state files
  (.sol-vault-keys.json, .football-tote-state.json,
  .tote-platform-state.json, .redeem-roundtrip-state.json,
  .eurc-onboard-state.json — some contain oracle privkeys / vault
  secretKeyBase58; NEVER commit) + the .usdm-historical-chart.html
  chart output + MS Office `~$*` lock files + scripts/bundle-surfaces
  `build/` output. Also add scripts/bundle-surfaces.mjs.
- CLAUDE.md, WALLET-COORDINATION.md, snapshots/INDEX.md, design/README.md
  refreshed.
- package.json / package-lock.json bumps.

Verified: sensitive files at repo root confirmed ignored (git check-ignore
each). No `.env`, no raw WIF/xprv/mnemonic/secretKey/oraclePriv strings in
the staged diff. MS Word autosave file (`Parameters/Philosophy/~$*.docx`)
excluded and gitignored.

The WizardConnect responder work landed separately in the previous commit
(6987591); this is everything else that had accumulated alongside it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-07-29 01:14:33 +02:00

122 lines
9.6 KiB
JavaScript

#!/usr/bin/env node
/**
* chipnet-mint-pyusd-solana.mjs — the BCH-mint half of PYUSD·Solana onboarding, against the ALREADY
* real-locked PYUSD on Solana devnet (see onboard-pyusd-solana-real.mjs; lock sig recorded below).
*
* Decoupled from the Solana leg (which is proven three times on devnet) so the chipnet mint runs on a
* fresh operator wallet (D) — the earlier all-in-one runs churned wallet C's UTXO set ("Missing
* inputs"). Mints 3 USD into the PYUSD.Solana cell of a Uniform USD aggregate basket, reconciling
* against the real 3 PYUSD in the operator vault. Run: node --import tsx scripts/chipnet-mint-pyusd-solana.mjs --yes
*/
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
import { join } from 'node:path';
import { TestNetWallet } from 'mainnet-js';
import { Contract as CashContract, ElectrumNetworkProvider, TransactionBuilder, SignatureTemplate } from 'cashscript';
import { secp256k1, sha256 as laSha256 } from '@bitauth/libauth';
import { codeOf } from '../services/uniform-registry/ledger.mjs';
import { buildLedger } from '../services/uniform-registry/registry.mjs';
import { safeUtxos, pickBch as pickSafe, eligibleVout0, sendWithRetry } from './lib/chipnet-safe.mjs';
const ROOT = join(import.meta.dirname, '..');
const ART = JSON.parse(readFileSync(join(ROOT, 'contracts/dist/UniformReserveAggregate.json'), 'utf8'));
// operator/funder wallet — configurable so we can validate the stale-UTXO fix on the CHURNED wallet C
const WALLET = (process.argv.find((a) => a.startsWith('--wallet=')) || '--wallet=c').split('=')[1];
const KEYS = { c: join(ROOT, '.chipnet-keys-c.json'), d: join(ROOT, '.chipnet-keys-d.json'), b: join(ROOT, '.chipnet-keys-b.json'), e: join(ROOT, '.chipnet-keys-e.json'), f: join(ROOT, '.chipnet-keys-f.json'), g: join(ROOT, '.chipnet-keys-g.json') };
const SOL_LOCK_SIG = '4fcMGdDhXbQ6rw9dvjey5NbPNMMMmvM1omFTwp4MjUDtyLUYvhThruVj62nsDwaKgazfVreMomuqELiXjjBf6PmN';
const LOCKED = 3_000_000n; // 3 PYUSD really locked in the Solana operator vault
const SUPPLY = 1_000_000_000n, FX_SCALE = 1_000_000n, FX_BAND = 0n;
const DUST = 1000n, MF = 12_000n;
const hexToBin = (h) => { const o = new Uint8Array(h.length / 2); for (let i = 0; i < o.length; i++) o[i] = parseInt(h.slice(i * 2, i * 2 + 2), 16); return o; };
const binToHex = (b) => [...b].map((x) => x.toString(16).padStart(2, '0')).join('');
const txidLE = (h) => { const d = hexToBin(h); const o = new Uint8Array(d.length); for (let i = 0; i < d.length; i++) o[i] = d[d.length - 1 - i]; return o; };
const p2pkh = (pkh) => { const o = new Uint8Array(25); o[0] = 0x76; o[1] = 0xa9; o[2] = 0x14; o.set(pkh, 3); o[23] = 0x88; o[24] = 0xac; return o; };
const u32le = (n) => { const b = new Uint8Array(4); new DataView(b.buffer).setUint32(0, Number(n), true); return b; };
const u64le = (n) => { const b = new Uint8Array(8); new DataView(b.buffer).setBigUint64(0, BigInt(n), true); return b; };
const oSign = (priv, msg) => { const s = secp256k1.signMessageHashSchnorr(priv, laSha256.hash(msg)); if (typeof s === 'string') throw new Error(s); return s; };
const EMPTY = new Uint8Array(0);
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
const div = (c = '=') => console.log(c.repeat(84));
const step = (t) => { console.log(''); div(); console.log(t); div(); };
const txidOf = (s) => (typeof s === 'string' ? s : s?.txid ?? s?.txId);
const fmt = (n) => (Number(n) / 1e6).toFixed(2);
const commit = (agg, root) => binToHex(u64le(agg)) + binToHex(root);
const depositMsg = (lb, minted, root, ctrl) => { const m = new Uint8Array(101); m.set(lb, 0); m.set(u64le(minted), 25); m.set(root, 33); m.set(txidLE(ctrl.txid), 65); m.set(u32le(ctrl.vout), 97); return m; };
const pickBch = (u, need) => { const p = []; let t = 0n; for (const x of u) { p.push(x); t += BigInt(x.satoshis); if (t >= need) break; } return { p, t }; };
async function main() {
if (!process.argv.includes('--yes')) { console.log('Re-run with --yes to broadcast on chipnet.'); return; }
for (const k of ['e', 'f', 'g']) if (!existsSync(KEYS[k])) { const w = await TestNetWallet.newRandom(); writeFileSync(KEYS[k], JSON.stringify({ wif: w.privateKeyWif }, null, 2)); }
const D = await TestNetWallet.fromWIF(JSON.parse(readFileSync(KEYS[WALLET], 'utf8')).wif); // operator/funder
const ALICE = await TestNetWallet.fromWIF(JSON.parse(readFileSync(KEYS.b, 'utf8')).wif); // user/recipient
const [E, F, G] = await Promise.all(['e', 'f', 'g'].map(async (k) => TestNetWallet.fromWIF(JSON.parse(readFileSync(KEYS[k], 'utf8')).wif)));
const provider = new ElectrumNetworkProvider('chipnet');
const sigD = new SignatureTemplate(D.privateKey);
const quorum = (msg) => [oSign(E.privateKey, msg), oSign(F.privateKey, msg), EMPTY];
const instance = (cat) => new CashContract(ART, [txidLE(cat), E.publicKey, F.publicKey, G.publicKey, SUPPLY, FX_SCALE, FX_BAND], { provider });
const ftBal = async (w, cat) => (await provider.getUtxos(w.cashaddr)).filter((x) => x.token?.category === cat && !x.token?.nft).reduce((s, x) => s + BigInt(x.token.amount), 0n);
const ctrlOf = async (inst, cat) => (await provider.getUtxos(inst.tokenAddress)).find((x) => x.token?.category === cat && x.token?.nft);
// SAFE selection: reconcile the cashscript + mainnet-js views (the cashscript chipnet server lists
// stale/spent outpoints) → spend only confirmed outpoints both agree exist. See lib/chipnet-safe.mjs.
const pick = async (need) => pickSafe(await safeUtxos(provider, D), need);
const ledger = buildLedger('USD', { supply: SUPPLY });
console.log(`operator/funder ${D.cashaddr} (wallet ${WALLET})\nuser ${ALICE.cashaddr}`);
console.log(`backing: ${fmt(LOCKED)} PYUSD really locked on Solana devnet · lock sig ${SOL_LOCK_SIG.slice(0, 16)}…`);
step('1. Genesis a Uniform USD aggregate basket');
let cat, inst;
await sendWithRetry(async () => {
const u0 = await eligibleVout0(provider, D); cat = u0.txid; inst = instance(cat);
const uSat = BigInt(u0.satoshis); const need = DUST + MF + 1000n;
const safe = (await safeUtxos(provider, D)).filter((x) => !x.token && !(x.txid === u0.txid && x.vout === u0.vout));
const { p, t } = pickSafe(safe, need > uSat ? need - uSat : 0n); const total = uSat + t;
const tb = new TransactionBuilder({ provider });
tb.addInput(u0, sigD.unlockP2PKH()); for (const x of p) tb.addInput(x, sigD.unlockP2PKH());
tb.addOutput({ to: inst.tokenAddress, amount: DUST, token: { amount: SUPPLY, category: cat, nft: { capability: 'mutable', commitment: commit(0n, new Uint8Array(32)) } } });
tb.addOutput({ to: D.cashaddr, amount: total - DUST - MF });
console.log(` USD basket · category ${cat.slice(0, 16)}… · ${txidOf(await tb.send())}`);
}, { onRetry: (n, m) => console.log(` ↻ genesis retry ${n} — dropped a stale input (${m.slice(0, 32)}…)`) });
await sleep(16000);
step('2. MINT — deposit the locked PYUSD into the PYUSD.Solana cell (attestation backed by the real lock)');
{
let ctrl; for (let i = 0; i < 8 && !ctrl; i++) { ctrl = await ctrlOf(inst, cat); if (!ctrl) await sleep(5000); }
if (!ctrl) throw new Error('genesis controller not visible');
// deterministic once: the off-chain ledger mutation + the outpoint-bound attestation
const { aggregate, root } = ledger.deposit(codeOf('PYUSD', 'Solana'), LOCKED);
const msg = depositMsg(p2pkh(ALICE.publicKeyHash), LOCKED, root, ctrl);
const q = quorum(msg);
// retry only RE-FETCHES the funding inputs (that's where a stale outpoint would sneak in)
await sendWithRetry(async () => {
const { p, t } = await pick(DUST + MF + 1000n);
const tb = new TransactionBuilder({ provider });
tb.addInput(ctrl, inst.unlock.deposit(...q, msg)); for (const x of p) tb.addInput(x, sigD.unlockP2PKH());
tb.addOutput({ to: inst.tokenAddress, amount: BigInt(ctrl.satoshis), token: { amount: BigInt(ctrl.token.amount) - LOCKED, category: cat, nft: { capability: 'mutable', commitment: commit(aggregate, root) } } });
tb.addOutput({ to: ALICE.tokenaddr, amount: DUST, token: { amount: LOCKED, category: cat } });
tb.addOutput({ to: D.cashaddr, amount: t - DUST - MF });
console.log(` minted ${fmt(LOCKED)} USD into PYUSD.Solana cell · aggregate ${fmt(aggregate)} · ${txidOf(await tb.send())}`);
}, { onRetry: (n, m) => console.log(` ↻ mint retry ${n} — dropped a stale funding input (${m.slice(0, 32)}…)`) });
await sleep(9000);
}
step('VERDICT — Solana locked == BCH minted');
const ctrl = await ctrlOf(inst, cat);
const aggOnchain = BigInt('0x' + [...hexToBin(ctrl.token.nft.commitment.slice(0, 16))].reverse().map((x) => x.toString(16).padStart(2, '0')).join(''));
const aliceUsd = await ftBal(ALICE, cat);
const cellVal = ledger.cells.get(codeOf('PYUSD', 'Solana')).value;
const checks = [
['3 PYUSD really locked on Solana devnet (proven, sig above)', true],
['equal USD minted on BCH (locked == minted)', aliceUsd === LOCKED],
['credited the PYUSD.Solana cell', cellVal === LOCKED],
['on-chain aggregate == off-chain ledger aggregate', aggOnchain === ledger.aggregate],
];
for (const [l, ok] of checks) console.log(` ${ok ? '✅' : '❌'} ${l}`);
console.log(`\n BCH: Alice holds ${fmt(aliceUsd)} unified USD · PYUSD.Solana cell ${fmt(cellVal)} · category ${cat.slice(0, 16)}…`);
const ok = checks.every(([, c]) => c);
console.log(ok
? '\nPYUSD·SOLANA ONBOARDED FOR REAL — a genuine Solana devnet PYUSD lock backs the minted USD on BCH.\nPYUSD is now a TWO-CHAIN issuer, BOTH legs real. Solana correspondent rail: BUILT + VALIDATED.'
: '\nSOME CHECKS FAILED.');
process.exit(ok ? 0 : 1);
}
main().catch((e) => { console.error('FAILED:', e?.message ?? e); process.exit(1); });