@okxweb3/coin-bitcoin
Version:
@okxweb3/coin-bitcoin is a Bitcoin SDK for building Web3 wallets and applications. It supports BTC, BSV, DOGE, LTC, and TBTC, enabling private key management, transaction signing, address generation, and inscriptions like BRC-20, Runes, CAT, and Atomicals
246 lines • 10.1 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getFee = exports.getDummySignature = exports.getDummyEcKey = exports.verifyContract = exports.toTokenAddress = exports.resetTx = exports.unScaleByDecimals = exports.scaleByDecimals = exports.toP2tr = exports.p2tr2Address = exports.toBitcoinNetwork = exports.toStateScript = exports.callToBufferList = exports.getDummyUTXO = exports.dummyUTXO = exports.getDummySigner = exports.outpoint2ByteString = exports.outpoint2TxOutpoint = exports.toTxOutpoint = exports.getTokenContractP2TR = exports.getTokenContract = exports.getGuardsP2TR = exports.GuardType = exports.script2P2TR = exports.contract2P2TR = exports.strToByteString = exports.byteStringToBuffer = exports.toXOnly = void 0;
const cat_smartcontracts_1 = require("@cat-protocol/cat-smartcontracts");
const common_1 = require("../common");
const scrypt_ts_1 = require("scrypt-ts");
const tapscript_1 = require("@cmdcode/tapscript");
const crypto_1 = require("crypto");
const decimal_js_1 = __importDefault(require("decimal.js"));
const eckey_1 = require("./eckey");
const ISSUE_PUBKEY = '0250929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0';
function toXOnly(pubkey) {
return pubkey.subarray(1, 33);
}
exports.toXOnly = toXOnly;
const byteStringToBuffer = function (byteStringList) {
const bufferList = [];
for (const byteString of byteStringList) {
bufferList.push(Buffer.from(byteString, 'hex'));
}
return bufferList;
};
exports.byteStringToBuffer = byteStringToBuffer;
function strToByteString(s) {
return (0, scrypt_ts_1.toByteString)(Buffer.from(s, 'utf-8').toString('hex'));
}
exports.strToByteString = strToByteString;
function contract2P2TR(contract) {
const script = contract.lockingScript.toBuffer();
const p2tr = script2P2TR(script);
return {
...p2tr,
script: script.toString('hex'),
contract,
};
}
exports.contract2P2TR = contract2P2TR;
function script2P2TR(script) {
const tapScript = tapscript_1.Tap.encodeScript(script);
const [p2tr, cblock] = tapscript_1.Tap.getPubKey(ISSUE_PUBKEY, {
target: tapScript,
});
return {
p2tr: new common_1.btc.Script(`OP_1 32 0x${p2tr}}`).toHex(),
tapScript: tapScript,
cblock,
};
}
exports.script2P2TR = script2P2TR;
var GuardType;
(function (GuardType) {
GuardType[GuardType["Transfer"] = 0] = "Transfer";
GuardType[GuardType["Burn"] = 1] = "Burn";
})(GuardType = exports.GuardType || (exports.GuardType = {}));
function getGuardsP2TR(guardType = GuardType.Transfer) {
const burnGuard = new cat_smartcontracts_1.BurnGuard();
const transferGuard = new cat_smartcontracts_1.TransferGuard();
const tapleafKeyBurnGuard = tapscript_1.Tap.encodeScript(burnGuard.lockingScript.toBuffer());
const tapleafKeyTransferGuard = tapscript_1.Tap.encodeScript(transferGuard.lockingScript.toBuffer());
const tapTree = [tapleafKeyBurnGuard, tapleafKeyTransferGuard];
const [tpubkeyGuards] = tapscript_1.Tap.getPubKey(ISSUE_PUBKEY, {
tree: tapTree,
});
const [, cblockKeyBurnGuard] = tapscript_1.Tap.getPubKey(ISSUE_PUBKEY, {
target: tapleafKeyBurnGuard,
tree: tapTree,
});
const [, cblockKeyTransferGuard] = tapscript_1.Tap.getPubKey(ISSUE_PUBKEY, {
target: tapleafKeyTransferGuard,
tree: tapTree,
});
const p2tr = new common_1.btc.Script(`OP_1 32 0x${tpubkeyGuards}}`).toHex();
if (guardType === GuardType.Transfer) {
return {
p2tr,
tapScript: tapleafKeyTransferGuard,
cblock: cblockKeyTransferGuard,
script: transferGuard.lockingScript.toBuffer().toString('hex'),
contract: transferGuard,
};
}
return {
p2tr,
tapScript: tapleafKeyBurnGuard,
cblock: cblockKeyBurnGuard,
script: burnGuard.lockingScript.toBuffer().toString('hex'),
contract: burnGuard,
};
}
exports.getGuardsP2TR = getGuardsP2TR;
function getTokenContract(minterP2TR, guardsP2TR) {
return new cat_smartcontracts_1.CAT20(minterP2TR, (0, scrypt_ts_1.toByteString)(guardsP2TR));
}
exports.getTokenContract = getTokenContract;
function getTokenContractP2TR(minterP2TR) {
const { p2tr: guardsP2TR } = getGuardsP2TR();
return contract2P2TR(getTokenContract(minterP2TR, guardsP2TR));
}
exports.getTokenContractP2TR = getTokenContractP2TR;
function toTxOutpoint(txid, outputIndex) {
const outputBuf = Buffer.alloc(4, 0);
outputBuf.writeUInt32LE(outputIndex);
return {
txhash: Buffer.from(txid, 'hex').reverse().toString('hex'),
outputIndex: outputBuf.toString('hex'),
};
}
exports.toTxOutpoint = toTxOutpoint;
function outpoint2TxOutpoint(outpoint) {
const [txid, vout] = outpoint.split('_');
return toTxOutpoint(txid, parseInt(vout));
}
exports.outpoint2TxOutpoint = outpoint2TxOutpoint;
const outpoint2ByteString = function (outpoint) {
const txOutpoint = outpoint2TxOutpoint(outpoint);
return txOutpoint.txhash + txOutpoint.outputIndex;
};
exports.outpoint2ByteString = outpoint2ByteString;
function getDummySigner(privateKey) {
return new scrypt_ts_1.TestWallet(scrypt_ts_1.bsv.PrivateKey.fromWIF('cRn63kHoi3EWnYeT4e8Fz6rmGbZuWkDtDG5qHnEZbmE5mGvENhrv'), new scrypt_ts_1.DummyProvider());
}
exports.getDummySigner = getDummySigner;
exports.dummyUTXO = {
txId: (0, crypto_1.randomBytes)(32).toString('hex'),
outputIndex: 0,
script: '',
satoshis: 10000,
};
function getDummyUTXO(satoshis = 10000, unique = false) {
if (unique) {
return Object.assign({}, exports.dummyUTXO, {
satoshis,
txId: (0, crypto_1.randomBytes)(32).toString('hex'),
});
}
return Object.assign({}, exports.dummyUTXO, { satoshis });
}
exports.getDummyUTXO = getDummyUTXO;
const callToBufferList = function (ct) {
const callArgs = ct.tx.inputs[ct.atInputIndex].script.chunks.map((value) => {
if (!value.buf) {
if (value.opcodenum >= 81 && value.opcodenum <= 96) {
const hex = (0, scrypt_ts_1.int2ByteString)(BigInt(value.opcodenum - 80));
return Buffer.from(hex, 'hex');
}
else {
return Buffer.from((0, scrypt_ts_1.toByteString)(''));
}
}
return value.buf;
});
return callArgs;
};
exports.callToBufferList = callToBufferList;
const toStateScript = function (state) {
return new common_1.btc.Script(`6a1863617401${state.hashRoot}`);
};
exports.toStateScript = toStateScript;
function toBitcoinNetwork(network) {
if (network === 'btc-signet') {
return common_1.btc.Networks.testnet;
}
else if (network === 'fractal-mainnet' || 'fractal-testnet') {
return common_1.btc.Networks.mainnet;
}
else {
throw new Error(`invalid network ${network}`);
}
}
exports.toBitcoinNetwork = toBitcoinNetwork;
function p2tr2Address(p2tr, network) {
const script = typeof p2tr === 'string' ? common_1.btc.Script.fromHex(p2tr) : p2tr;
return common_1.btc.Address.fromScript(script, toBitcoinNetwork(network)).toString();
}
exports.p2tr2Address = p2tr2Address;
function toP2tr(address) {
const p2trAddress = typeof address === 'string' ? common_1.btc.Address.fromString(address) : address;
if (p2trAddress.type !== 'taproot') {
throw new Error(`address ${address} is not taproot`);
}
return common_1.btc.Script.fromAddress(address).toHex();
}
exports.toP2tr = toP2tr;
function scaleByDecimals(amount, decimals) {
return amount * BigInt(Math.pow(10, decimals));
}
exports.scaleByDecimals = scaleByDecimals;
function unScaleByDecimals(amount, decimals) {
return new decimal_js_1.default(amount.toString().replace('n', ''))
.div(Math.pow(10, decimals))
.toFixed(decimals);
}
exports.unScaleByDecimals = unScaleByDecimals;
function resetTx(tx) {
for (let i = 0; i < tx.inputs.length; i++) {
const input = tx.inputs[i];
if (input.hasWitnesses()) {
input.setWitnesses([]);
}
}
tx.nLockTime = 0;
}
exports.resetTx = resetTx;
function toTokenAddress(address) {
if (typeof address === 'string') {
address = common_1.btc.Address.fromString(address);
}
if (address.type === common_1.btc.Address.PayToTaproot) {
return (0, scrypt_ts_1.hash160)(address.hashBuffer.toString('hex'));
}
else if (address.type === common_1.btc.Address.PayToWitnessPublicKeyHash) {
return address.hashBuffer.toString('hex');
}
else {
throw new Error(`Unsupported address type: ${address.type}`);
}
}
exports.toTokenAddress = toTokenAddress;
function verifyContract(utxo, tx, inputIndex, witnesses) {
const interpreter = new common_1.btc.Script.Interpreter();
const flags = common_1.btc.Script.Interpreter.SCRIPT_VERIFY_WITNESS
| common_1.btc.Script.Interpreter.SCRIPT_VERIFY_TAPROOT;
const res = interpreter.verify(new common_1.btc.Script(''), new common_1.btc.Script(utxo.script), tx, inputIndex, flags, witnesses, utxo.satoshis);
if (!res) {
return interpreter.errstr;
}
return true;
}
exports.verifyContract = verifyContract;
function getDummyEcKey() {
return new eckey_1.EcKeyService({ privateKey: 'L4EpxBBbTqztn8Q9W73Cf7e36ttHhDWRSzr4sHazjUcCrucwEJLy' });
}
exports.getDummyEcKey = getDummyEcKey;
function getDummySignature() {
return common_1.btc.crypto.Signature.fromString('E907831F80848D1069A5371B402410364BDF1C5F8307B0084C55F1CE2DCA821525F66A4A85EA8B71E482A74F382D2CE5EBEEE8FDB2172F477DF4900D310536C0').toString('hex');
}
exports.getDummySignature = getDummySignature;
function getFee(tx) {
return tx.inputs.reduce((acc, i) => acc + i.output.satoshis, 0)
- tx.outputs.reduce((acc, o) => acc + o.satoshis, 0);
}
exports.getFee = getFee;
//# sourceMappingURL=utils.js.map