UNPKG

@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

155 lines 6.99 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.unlockGuard = exports.unlockToken = exports.createGuardContract = void 0; const utils_1 = require("../utils"); const common_1 = require("../common"); const utils_2 = require("../utils"); const cat_smartcontracts_1 = require("@cat-protocol/cat-smartcontracts"); const scrypt_ts_1 = require("scrypt-ts"); function createGuardContract(ecKey, feeutxo, feeRate, tokens, tokenP2TR, changeAddress) { const { p2tr: guardP2TR, tapScript: guardTapScript } = (0, utils_2.getGuardsP2TR)(); const protocolState = cat_smartcontracts_1.ProtocolState.getEmptyState(); const realState = cat_smartcontracts_1.GuardProto.createEmptyState(); realState.tokenScript = tokenP2TR; for (let i = 0; i < tokens.length; i++) { realState.inputTokenAmountArray[i] = tokens[i].state.data.amount; } protocolState.updateDataList(0, cat_smartcontracts_1.GuardProto.toByteString(realState)); const commitTx = new common_1.btc.Transaction() .from(feeutxo) .addOutput(new common_1.btc.Transaction.Output({ satoshis: 0, script: (0, utils_2.toStateScript)(protocolState), })) .addOutput(new common_1.btc.Transaction.Output({ satoshis: common_1.Postage.GUARD_POSTAGE, script: guardP2TR, })) .feePerByte(feeRate) .change(changeAddress); if (commitTx.getChangeOutput() === null) { throw new Error('Insufficient satoshis balance!'); } commitTx.outputs[2].satoshis -= 1; if (ecKey.hasPrivateKey()) { ecKey.signTx(commitTx); } const contact = { utxo: { txId: commitTx.id, outputIndex: 1, script: commitTx.outputs[1].script.toHex(), satoshis: commitTx.outputs[1].satoshis, }, state: { protocolState, data: realState, }, }; return { commitTx, contact, guardTapScript, }; } exports.createGuardContract = createGuardContract; async function unlockToken(ecKey, tokenContract, tokenInputIndex, prevTokenTx, preTokenInputIndex, prevPrevTokenTx, guardInfo, revealTx, minterP2TR, txCtx, verify, signature, contractSpend, contractInputIndex) { const { cblock: cblockToken, contract: token } = (0, utils_2.getTokenContractP2TR)(minterP2TR); const { shPreimage, prevoutsCtx, spentScripts, sighash } = txCtx; let tokenUnlockArgs = { isUserSpend: false, userPubKeyPrefix: (0, scrypt_ts_1.toByteString)(''), userPubKey: (0, scrypt_ts_1.PubKey)(ecKey.getXOnlyPublicKey()), userSig: (0, utils_1.getDummySignature)(), contractInputIndex: BigInt(contractInputIndex || 0), }; if (!contractSpend) { let sig; if (ecKey.hasPrivateKey()) { sig = common_1.btc.crypto.Schnorr.sign(ecKey.getTokenPrivateKey(), sighash.hash); } else { sig = common_1.btc.crypto.Signature.fromString(signature); } const pubkeyX = ecKey.getXOnlyPublicKey(); const pubKeyPrefix = ecKey.getPubKeyPrefix(); tokenUnlockArgs = { isUserSpend: true, userPubKeyPrefix: pubKeyPrefix, userPubKey: (0, scrypt_ts_1.PubKey)(pubkeyX), userSig: sig.toString('hex'), contractInputIndex: 0n, }; } const backtraceInfo = (0, cat_smartcontracts_1.getBackTraceInfo)(prevTokenTx, prevPrevTokenTx, preTokenInputIndex); const { state: { protocolState, data: preState }, } = tokenContract; await token.connect((0, utils_2.getDummySigner)()); const preTxState = { statesHashRoot: protocolState.hashRoot, txoStateHashes: protocolState.stateHashList, }; const tokenCall = await token.methods.unlock(tokenUnlockArgs, preState, preTxState, guardInfo, backtraceInfo, shPreimage, prevoutsCtx, spentScripts, { fromUTXO: (0, utils_2.getDummyUTXO)(), verify: false, exec: false, }); const witnesses = [ ...(0, utils_2.callToBufferList)(tokenCall), token.lockingScript.toBuffer(), Buffer.from(cblockToken, 'hex'), ]; revealTx.inputs[tokenInputIndex].witnesses = witnesses; if (verify) { const res = (0, utils_2.verifyContract)(tokenContract.utxo, revealTx, tokenInputIndex, witnesses); if (typeof res === 'string') { throw new Error(`unlocking token contract at input ${tokenInputIndex} failed! ${res}`); } return true; } return true; } exports.unlockToken = unlockToken; async function unlockGuard(guardContract, guardInfo, guardInputIndex, newState, revealTx, receiverTokenState, changeTokenState, changeInfo, txCtx, verify) { const { shPreimage, prevoutsCtx, spentScripts } = txCtx; const outputArray = (0, cat_smartcontracts_1.emptyTokenArray)(); const tokenAmountArray = (0, cat_smartcontracts_1.emptyTokenAmountArray)(); const tokenOutputIndexArray = (0, scrypt_ts_1.fill)(false, cat_smartcontracts_1.MAX_TOKEN_OUTPUT); outputArray[0] = receiverTokenState.ownerAddr; tokenAmountArray[0] = receiverTokenState.amount; tokenOutputIndexArray[0] = true; if (changeTokenState) { outputArray[1] = changeTokenState.ownerAddr; tokenAmountArray[1] = changeTokenState.amount; tokenOutputIndexArray[1] = true; } const satoshiChangeOutputIndex = changeTokenState === null ? 1 : 2; const { cblock: transferCblock, contract: transferGuard } = (0, utils_2.getGuardsP2TR)(); await transferGuard.connect((0, utils_2.getDummySigner)()); const outpointSatoshiArray = (0, cat_smartcontracts_1.emptyTokenArray)(); if (changeInfo != null) { outpointSatoshiArray[satoshiChangeOutputIndex] = changeInfo.satoshis; outputArray[satoshiChangeOutputIndex] = changeInfo.script; tokenOutputIndexArray[satoshiChangeOutputIndex] = false; } const transferGuardCall = await transferGuard.methods.transfer(newState.stateHashList, outputArray, tokenAmountArray, tokenOutputIndexArray, outpointSatoshiArray, (0, scrypt_ts_1.int2ByteString)(BigInt(common_1.Postage.TOKEN_POSTAGE), 8n), guardContract.state.data, guardInfo.tx, shPreimage, prevoutsCtx, spentScripts, { fromUTXO: (0, utils_2.getDummyUTXO)(), verify: false, exec: false, }); const witnesses = [ ...(0, utils_2.callToBufferList)(transferGuardCall), transferGuard.lockingScript.toBuffer(), Buffer.from(transferCblock, 'hex'), ]; revealTx.inputs[guardInputIndex].witnesses = witnesses; if (verify) { const res = (0, utils_2.verifyContract)(guardContract.utxo, revealTx, guardInputIndex, witnesses); if (typeof res === 'string') { throw new Error(`unlocking guard contract failed! ${res}`); } return true; } return true; } exports.unlockGuard = unlockGuard; //# sourceMappingURL=functions.js.map