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>
71 lines
3.1 KiB
JavaScript
71 lines
3.1 KiB
JavaScript
/**
|
|
* LIVE chipnet proof for the noble crypto shim (ADR-0023).
|
|
*
|
|
* Run with the crypto-shim loader so EVERY libauth crypto call is served by
|
|
* pure-JS noble, with no WASM:
|
|
*
|
|
* node --import tsx --import ./scripts/crypto-shim-register.mjs \
|
|
* scripts/live-noble-send.mjs
|
|
*
|
|
* It exercises the EXACT signing path src/wallet/shell-runtime.ts uses:
|
|
* cashscript's `TransactionBuilder` + `SignatureTemplate(priv, _, ECDSA)`
|
|
* `.unlockP2PKH()`. Under the shim, the P2PKH sighash (double-SHA-256) and the
|
|
* ECDSA signature are produced entirely by noble. It self-sends a small amount
|
|
* of plain BCH (A → A) and confirms the tx lands on chain by re-querying it.
|
|
*/
|
|
import { readFileSync } from 'node:fs';
|
|
import { join } from 'node:path';
|
|
import { TestNetWallet } from 'mainnet-js';
|
|
import { ElectrumNetworkProvider, TransactionBuilder, SignatureTemplate, SignatureAlgorithm } from 'cashscript';
|
|
|
|
const ROOT = join(import.meta.dirname, '..');
|
|
|
|
if (!globalThis.__DEVIANT_NOBLE_SHIM_ACTIVE__) {
|
|
throw new Error(
|
|
'Crypto shim is NOT active — run with `--import ./scripts/crypto-shim-register.mjs`. ' +
|
|
'Refusing to claim a shim-backed broadcast without the shim wired in.',
|
|
);
|
|
}
|
|
console.log(`✓ noble crypto shim active (libauth WASM bypassed; marker=${globalThis.__DEVIANT_NOBLE_SHIM_ACTIVE__})`);
|
|
|
|
const SEND_SATS = BigInt(process.env.SATS ?? '5000');
|
|
const FEE = 300n;
|
|
|
|
async function main() {
|
|
const { wif } = JSON.parse(readFileSync(join(ROOT, '.chipnet-keys.json'), 'utf8'));
|
|
const sender = await TestNetWallet.fromWIF(wif);
|
|
const provider = new ElectrumNetworkProvider('chipnet');
|
|
|
|
// Pick a plain (non-token) UTXO with room for the send + fee.
|
|
const utxos = await provider.getUtxos(sender.cashaddr);
|
|
const plain = utxos
|
|
.filter((u) => !u.token && u.satoshis >= SEND_SATS + FEE)
|
|
.sort((a, b) => Number(a.satoshis - b.satoshis));
|
|
const input = plain[0];
|
|
if (!input) throw new Error('No spendable plain BCH UTXO found.');
|
|
const change = input.satoshis - SEND_SATS - FEE;
|
|
|
|
console.log(`Input ${input.txid.slice(0, 12)}…:${input.vout} = ${input.satoshis} sats`);
|
|
console.log(`Self-send ${SEND_SATS} sats (+${change} change) to ${sender.cashaddr}, fee ${FEE}`);
|
|
|
|
// The exact construction shell-runtime.ts uses: ECDSA P2PKH unlocker.
|
|
const template = new SignatureTemplate(sender.privateKey, undefined, SignatureAlgorithm.ECDSA);
|
|
const tb = new TransactionBuilder({ provider });
|
|
tb.addInput(input, template.unlockP2PKH());
|
|
tb.addOutput({ to: sender.cashaddr, amount: SEND_SATS });
|
|
if (change > 546n) tb.addOutput({ to: sender.cashaddr, amount: change });
|
|
|
|
const sent = await tb.send();
|
|
const txid = typeof sent === 'string' ? sent : (sent.txid ?? sent.txId);
|
|
console.log(`\nBroadcast TXID: ${txid}`);
|
|
|
|
const raw = await provider.getRawTransaction(txid);
|
|
console.log(`On-chain confirmation: getRawTransaction returned ${raw.length / 2} bytes for ${txid}`);
|
|
console.log('✓ chipnet accepted a P2PKH tx whose ECDSA signature + sighash were produced by the noble shim.');
|
|
}
|
|
|
|
main().catch((err) => {
|
|
console.error('FAILED:', err?.message ?? err);
|
|
if (err?.stack) console.error(err.stack);
|
|
process.exit(1);
|
|
});
|