Resolve "WIP: UTXO Selection and Storage"

This commit is contained in:
Jim Hamill
2025-01-11 08:39:24 +00:00
parent f934216d68
commit 33fd9bac4d
156 changed files with 13304 additions and 4595 deletions
@@ -0,0 +1,605 @@
import {
Address,
BlockHeader,
Bytes,
encodeExtendedJson,
decodeExtendedJson,
Hasher,
HDPrivateNode,
HDPublicNode,
Mnemonic,
PrivateKey,
PublicKey,
Satoshis,
Script,
Transaction,
} from '@xocash/primitives';
export const address = {
from: [
{
label: 'From',
inputs: ['CashAddr or Legacy Address'],
models: [''],
callback: (args: [string]) => Address.from(...args),
extendedInput: true,
},
{
label: 'From CashAddr',
inputs: ['CashAddr'],
models: [''],
callback: (args: [string]) => Address.fromCashAddr(...args),
extendedInput: true,
},
{
label: 'From Legacy',
inputs: ['Legacy Address'],
models: [''],
callback: (args: [string]) => Address.fromLegacy(...args),
extendedInput: true,
},
{
label: 'From Redeem Script Hex (P2SH20)',
inputs: ['RedeemScript Hex'],
models: [''],
callback: (args: [string]) =>
Address.fromRedeemScriptHex(...args, 'P2SH20'),
extendedInput: true,
},
{
label: 'From Redeem Script Hex (P2SH32)',
inputs: ['RedeemScript Hex'],
models: [''],
callback: (args: [string]) =>
Address.fromRedeemScriptHex(...args, 'P2SH32'),
extendedInput: true,
},
{
label: 'From Lockscript Hex',
inputs: ['Lockscript Hex'],
models: [''],
callback: (args: [string]) => Address.fromLockscriptHex(...args),
extendedInput: true,
},
{
label: 'From Hash160 Hex',
inputs: ['Hash160 Hex'],
models: [''],
callback: (args: [string]) => Address.fromHash160Hex(...args),
extendedInput: true,
},
],
to: [
{
label: 'To CashAddr (mainnet)',
callback: (address: Address) => address.toCashAddr('bitcoincash'),
},
{
label: 'To CashAddr (testnet)',
callback: (address: Address) => address.toCashAddr('bchtest'),
},
{
label: 'To CashAddr (regtest)',
callback: (address: Address) => address.toCashAddr('bchreg'),
},
{
label: 'To TokenAware CashAddr (mainnet)',
callback: (address: Address) => address.toTokenAddress('bitcoincash'),
},
{
label: 'To TokenAware CashAddr (testnet)',
callback: (address: Address) => address.toTokenAddress('bchtest'),
},
{
label: 'To TokenAware CashAddr (regtest)',
callback: (address: Address) => address.toTokenAddress('bchreg'),
},
{
label: 'To Legacy',
callback: (address: Address) => address.toLegacy(),
},
{
label: 'To Hash160/RIPEMD Hex',
callback: (address: Address) => address.toHash160Hex(),
},
{
label: 'To Lockscript Hex',
callback: (address: Address) => address.toLockscriptHex(),
},
{
label: 'To Lockscript ASM',
callback: (address: Address) => address.toLockscriptAsm(),
},
],
};
export const blockHeader = {
from: [
{
label: 'From Hex',
inputs: ['UTF-8'],
models: [''],
callback: (args: [string]) => BlockHeader.fromHex(...args),
},
],
to: [
{
label: 'To Raw',
callback: (blockHeader: BlockHeader) => blockHeader.toRaw(),
},
{
label: 'Version',
callback: (blockHeader: BlockHeader) => blockHeader.getVersion(),
},
{
label: 'Previous Block Hash',
callback: (blockHeader: BlockHeader) =>
blockHeader.getPreviousBlockHashHex(),
},
{
label: 'Merkle Root',
callback: (blockHeader: BlockHeader) => blockHeader.getMerkleRootHex(),
},
{
label: 'Timestamp',
callback: (blockHeader: BlockHeader) =>
blockHeader.getTimestamp().toString(),
},
{
label: 'Bits',
callback: (blockHeader: BlockHeader) => blockHeader.getBits().toString(),
},
{
label: 'Nonce',
callback: (blockHeader: BlockHeader) => blockHeader.getNonce().toString(),
},
],
};
export const bytes = {
from: [
{
label: 'From Base64',
inputs: ['Base64'],
models: [''],
callback: (args: [string]) => Bytes.fromBase64(...args),
},
{
label: 'From Hex',
inputs: ['Hex'],
models: [''],
callback: (args: [string]) => Bytes.fromHex(...args),
},
{
label: 'From UTF-8',
inputs: ['UTF-8'],
models: [''],
callback: (args: [string]) => Bytes.fromUtf8(...args),
},
],
to: [
{
label: 'To Base64',
callback: (bytes: Bytes) => bytes.toBase64(),
},
{
label: 'To Hex',
callback: (bytes: Bytes) => bytes.toHex(),
},
{
label: 'To UTF-8',
callback: (bytes: Bytes) => bytes.toUtf8(),
},
],
};
export const hasher = {
from: [
{
label: 'From Hex',
inputs: ['Hex'],
models: [''],
callback: (args: [string]) => Hasher.fromHex(...args),
},
{
label: 'From Base64',
inputs: ['Base64'],
models: [''],
callback: (args: [string]) => Hasher.fromBase64(...args),
},
{
label: 'From UTF-8',
inputs: ['UTF-8'],
models: [''],
callback: (args: [string]) => Hasher.fromUTF8(...args),
},
],
to: [
{
label: 'To Sha256 Hex',
callback: (hasher: Hasher) => hasher.toSHA256Hex(),
},
{
label: 'To RipeMD160 Hex',
callback: (hasher: Hasher) => hasher.toRIPEMD160Hex(),
},
{
label: 'To Hash160 Hex',
callback: (hasher: Hasher) => hasher.toHash160Hex(),
},
{
label: 'To Hash256 Hex',
callback: (hasher: Hasher) => hasher.toHash256Hex(),
},
],
};
export const hdPrivateNode = {
from: [
{
label: 'Generate Random',
inputs: ['Derivation Path'],
models: ["m/44'/145'/0'/0/1"],
callback: () => HDPrivateNode.generateRandom(),
},
{
label: 'From Mnemonic',
inputs: ['Mnemonic', 'Derivation Path'],
models: ['', "m/44'/145'/0'/0/1"],
callback: (args: [string]) => HDPrivateNode.fromMnemonic(...args),
},
{
label: 'From XPriv Key',
inputs: ['XPriv Key', 'Derivation Path'],
models: ['', "m/44'/145'/0'/0/1"],
callback: (args: [string]) => HDPrivateNode.fromXPriv(...args),
},
{
label: 'From Raw',
inputs: ['Raw (LibAuth Format/ExtJSON Encoded)'],
models: [''],
callback: (args: [string]) =>
HDPrivateNode.fromRaw(decodeExtendedJson(args.join(''))),
extendedInput: true,
},
],
to: [
{
label: 'To XPriv Key',
callback: (hdPrivateNode: HDPrivateNode) => hdPrivateNode.toXPriv(),
},
{
label: 'To String',
callback: (hdPrivateNode: HDPrivateNode) => hdPrivateNode.toString(),
},
{
label: 'To Raw (LibAuth Format/ExtJSON Encoded)',
callback: (hdPrivateNode: HDPrivateNode) =>
encodeExtendedJson(hdPrivateNode.toRaw(), 2),
},
{
label: 'To XPub Key',
callback: (hdPrivateNode: HDPrivateNode) =>
hdPrivateNode.deriveHDPublicNode().toXPub(),
},
],
};
export const hdPublicNode = {
from: [
{
label: 'From XPub Key',
inputs: ['XPub Key'],
models: [''],
callback: (args: [string]) => HDPublicNode.fromXPub(...args),
},
{
label: 'From Raw',
inputs: ['Raw (LibAuth Format/ExtJSON Encoded)'],
models: [''],
callback: (args: [string]) =>
HDPublicNode.fromRaw(decodeExtendedJson(args.join(''))),
extendedInput: true,
},
],
to: [
{
label: 'To XPub Key',
callback: (hdPublicNode: HDPublicNode) => hdPublicNode.toXPub(),
},
{
label: 'To String',
callback: (hdPublicNode: HDPublicNode) => hdPublicNode.toString(),
},
{
label: 'To Raw (LibAuth Format/ExtJSON Encoded)',
callback: (hdPublicNode: HDPublicNode) =>
encodeExtendedJson(hdPublicNode.toRaw(), 2),
},
],
};
export const mnemonic = {
from: [
{
label: 'Generate Random',
callback: () => Mnemonic.generateRandom(),
},
{
label: 'From String',
inputs: ['String'],
models: [''],
callback: (args: [string]) => Mnemonic.fromString(...args),
extendedInput: true,
},
],
to: [
{
label: 'To String (without passphrase)',
callback: (mnemonic: Mnemonic) => mnemonic.toString(false),
},
{
label: 'To String (with passphrase)',
callback: (mnemonic: Mnemonic) => mnemonic.toString(true),
},
{
label: 'Words',
callback: (mnemonic: Mnemonic) => mnemonic.toWords(),
},
{
label: 'Passphrase',
callback: (mnemonic: Mnemonic) => mnemonic.getPassphrase(),
},
],
};
// TODO: Message Signing outputs. Maybe add an `extension` flag to the `to` that allows another input field and uses that to generate the outputs
export const privateKey = {
from: [
{
label: 'Generate Random',
callback: () => PrivateKey.generateRandom(),
},
{
label: 'From Hex',
inputs: ['Hex'],
models: [''],
callback: (args: [string]) => PrivateKey.fromHex(...args),
},
{
label: 'From WIF',
inputs: ['WIF'],
models: [''],
callback: (args: [string]) => PrivateKey.fromWIF(...args),
},
],
to: [
{
label: 'To Hex',
callback: (privateKey: PrivateKey) => privateKey.toHex(),
},
{
label: 'To WIF',
callback: (privateKey: PrivateKey) => privateKey.toWif(),
},
{
label: 'To String',
callback: (privateKey: PrivateKey) => privateKey.toString(),
},
{
label: 'Derived Public Key (Hex)',
callback: (privateKey: PrivateKey) =>
privateKey.derivePublicKey().toString(),
},
{
label: 'Derived BCH Address (CashAddr)',
callback: (privateKey: PrivateKey) =>
privateKey.derivePublicKey().deriveAddress().toCashAddr('bitcoincash'),
},
],
methods: [
{
label: 'Sign Message (Schnorr)',
inputs: ['UTF8'],
models: ['Your text here'],
callback: (privateKey: PrivateKey, args: [string]) =>
Bytes.fromBytes(privateKey.signMessageSchnorr(...args)).toHex(),
},
{
label: 'Sign Message (DER)',
inputs: ['UTF8'],
models: ['Your text here'],
callback: (privateKey: PrivateKey, args: [string]) =>
Bytes.fromBytes(privateKey.signMessageDER(...args)).toHex(),
},
],
};
export const publicKey = {
from: [
{
label: 'From Hex',
inputs: ['Hex'],
models: [''],
callback: (args: [string]) => PublicKey.fromHex(...args),
},
{
label: 'From WIF',
inputs: ['WIF'],
models: [''],
callback: (args: [string]) =>
PrivateKey.fromWIF(...args).derivePublicKey(),
},
],
to: [
{
label: 'Derived Hash160 Hex',
callback: (publicKey: PublicKey) => publicKey.deriveHash160Hex(),
},
{
label: 'Derived Address',
callback: (publicKey: PublicKey) =>
publicKey.deriveAddress().toCashAddr(),
},
{
label: 'To Hex',
callback: (publicKey: PublicKey) => publicKey.toHex(),
},
{
label: 'To String',
callback: (publicKey: PublicKey) => publicKey.toString(),
},
],
methods: [
{
label: 'Verify Message (Schnorr)',
inputs: ['Message (UTF8)', 'Signature (Hex)'],
models: ['Your text here'],
callback: (publicKey: PublicKey, args: [string, string]) =>
publicKey.verifyMessageSchnorr(...args).toString(),
},
{
label: 'Verify Message (DER)',
inputs: ['Message (UTF8)', 'Signature (Hex)'],
models: ['Your text here'],
callback: (publicKey: PublicKey, args: [string, string]) =>
publicKey.verifyMessageDER(...args).toString(),
},
],
};
export const satoshis = {
from: [
{
label: 'From Sats',
inputs: ['Sats'],
models: [''],
callback: (args: [number]) => Satoshis.fromSats(...args),
},
{
label: 'From Bits',
inputs: ['Bits'],
models: [''],
callback: (args: [number]) => Satoshis.fromBits(...args),
},
{
label: 'From MBCH',
inputs: ['MBCH'],
models: [''],
callback: (args: [number]) => Satoshis.fromMBCH(...args),
},
{
label: 'From BCH',
inputs: ['BCH'],
models: [''],
callback: (args: [number]) => Satoshis.fromBCH(...args),
},
],
to: [
{
label: 'To Sats',
callback: (satoshis: Satoshis) => satoshis.toSats().toString(),
},
{
label: 'To Bits',
callback: (satoshis: Satoshis) => satoshis.toBits().toString(),
},
{
label: 'To MBCH',
callback: (satoshis: Satoshis) => satoshis.toMBCH().toString(),
},
{
label: 'To BCH',
callback: (satoshis: Satoshis) => satoshis.toBCH().toString(),
},
],
};
export const script = {
from: [
{
label: 'From ASM',
inputs: ['ASM'],
models: [''],
callback: (args: [string]) => Script.fromASM(...args),
},
{
label: 'From Hex',
inputs: ['Hex'],
models: [''],
callback: (args: [string]) => Script.fromHex(...args),
},
],
to: [
{
label: 'To ASM',
callback: (script: Script) => script.toASM(),
},
{
label: 'To Hex',
callback: (script: Script) => script.toHex(),
},
],
};
export const transaction = {
from: [
{
label: 'From Hex',
inputs: ['Hex'],
models: [''],
callback: (args: [string]) => Transaction.fromHex(...args),
extendedInput: true,
},
{
label: 'From Raw',
inputs: ['Raw (LibAuth Format/ExtJSON Encoded)'],
models: [''],
callback: (args: [...string[]]) =>
Transaction.fromRaw(decodeExtendedJson(args.join(''))),
extendedInput: true,
},
],
to: [
{
label: 'To Transaction Hash Hex',
callback: (transaction: Transaction) => transaction.toHashHex(),
},
{
label: 'To Raw (LibAuth Format/ExtJSON Encoded)',
callback: (transaction: Transaction) =>
encodeExtendedJson(transaction.toRaw(), 2),
},
{
label: 'To Hex',
callback: (transaction: Transaction) => transaction.toHex(),
},
{
label: 'Version',
callback: (transaction: Transaction) =>
transaction.getVersion().toString(),
},
{
label: 'Inputs',
callback: (transaction: Transaction) => {
return encodeExtendedJson(transaction.getInputs(), 2);
},
},
{
label: 'Outputs',
callback: (transaction: Transaction) => {
return encodeExtendedJson(transaction.getOutputs(), 2);
},
},
{
label: 'Locktime',
callback: (transaction: Transaction) =>
transaction.getLocktime().toString(),
},
{
label: 'Is Coinbase',
callback: (transaction: Transaction) =>
transaction.isCoinbase().toString(),
},
],
};