UNPKG

meta-contract-debug

Version:

Meta Contract SDK

211 lines (210 loc) 9.38 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.parseSensibleId = exports.getLatestGenesisInfo = exports.getNftInfo = exports.checkFeeRate = exports.unlockP2PKHInputs = exports.addChangeOutput = exports.addOpreturnOutput = exports.addContractOutput = exports.addContractInput = exports.addP2PKHInputs = exports.prepareUtxos = void 0; const mvc_1 = require("../mvc"); const error_1 = require("../common/error"); const utils_1 = require("../common/utils"); const nftGenesis_1 = require("../mcp01/contract-factory/nftGenesis"); const tokenGenesis_1 = require("../mcp02/contract-factory/tokenGenesis"); const nftProto = require("../mcp01/contract-proto/nft.proto"); const ftProto = require("../mcp02/contract-proto/token.proto"); const mvc = require("../mvc"); function prepareUtxos(purse, api, network, utxosInput) { return __awaiter(this, void 0, void 0, function* () { let utxoPrivateKeys = []; if (utxosInput) { utxosInput.forEach((utxo) => { if (utxo.wif) { let privateKey = mvc.PrivateKey.fromWIF(utxo.wif); utxoPrivateKeys.push(privateKey); utxo.address = privateKey.toAddress(network); //Compatible with the old version, only wif is provided but no address is provided } }); return { utxos: utxosInput, utxoPrivateKeys, }; } const utxos = yield api.getUnspents(purse.address.toString()); utxos.forEach((utxo) => { utxoPrivateKeys.push(purse.privateKey); utxo.address = new mvc_1.Address(utxo.address, network); }); if (utxos.length == 0) throw new error_1.CodeError(error_1.ErrCode.EC_INSUFFICIENT_BSV, 'Insufficient balance.'); return { utxos, utxoPrivateKeys }; }); } exports.prepareUtxos = prepareUtxos; function addP2PKHInputs(txComposer, utxos) { const p2pkhInputIndexes = utxos.map((utxo) => { const inputIndex = txComposer.appendP2PKHInput(utxo); txComposer.addSigHashInfo({ inputIndex, address: utxo.address.toString(), sighashType: utils_1.sighashType, contractType: utils_1.CONTRACT_TYPE.P2PKH, }); return inputIndex; }); return p2pkhInputIndexes; } exports.addP2PKHInputs = addP2PKHInputs; function addContractInput(txComposer, contractUTxo, address, contractType) { const contractInputIndex = txComposer.appendInput(contractUTxo); txComposer.addSigHashInfo({ inputIndex: contractInputIndex, address, sighashType: utils_1.sighashType, contractType, }); return contractInputIndex; } exports.addContractInput = addContractInput; function addContractOutput({ txComposer, contract, lockingScript, dustCalculator, }) { if (!lockingScript) { lockingScript = contract.lockingScript; } const contractSize = lockingScript.toBuffer().length; const satoshis = dustCalculator.getDustThreshold(contractSize); return txComposer.appendOutput({ lockingScript, satoshis, }); } exports.addContractOutput = addContractOutput; function addOpreturnOutput(txComposer, opreturnData) { return txComposer.appendOpReturnOutput(opreturnData); } exports.addOpreturnOutput = addOpreturnOutput; function addChangeOutput(txComposer, changeAddress, feeb) { return txComposer.appendChangeOutput(changeAddress, feeb); } exports.addChangeOutput = addChangeOutput; function unlockP2PKHInputs(txComposer, inputIndexes, utxoPrivateKeys) { inputIndexes.forEach((inputIndex) => { let privateKey = utxoPrivateKeys.splice(0, 1)[0]; txComposer.unlockP2PKHInput(privateKey, inputIndex); }); } exports.unlockP2PKHInputs = unlockP2PKHInputs; function checkFeeRate(txComposer, feeb) { let feeRate = txComposer.getFeeRate(); if (feeRate < feeb) { throw new error_1.CodeError(error_1.ErrCode.EC_INSUFFICIENT_BSV, `Insufficient balance.The fee rate should not be less than ${feeb}, but in the end it is ${feeRate}.`); } } exports.checkFeeRate = checkFeeRate; function getNftInfo({ tokenIndex, codehash, genesis, api, network, }) { return __awaiter(this, void 0, void 0, function* () { let _res = yield api.getNonFungibleTokenUnspentDetail(codehash, genesis, tokenIndex); let nftUtxo = { txId: _res.txId, outputIndex: _res.outputIndex, nftAddress: new mvc_1.Address(_res.tokenAddress, network), }; return { nftUtxo }; }); } exports.getNftInfo = getNftInfo; // 获取最新的创世合约及tx信息 function getLatestGenesisInfo({ sensibleId, api, address, type, }) { return __awaiter(this, void 0, void 0, function* () { const factory = type === 'nft' ? nftGenesis_1.NftGenesisFactory : tokenGenesis_1.TokenGenesisFactory; const proto = type === 'nft' ? nftProto : ftProto; let genesisContract = factory.createContract(); let { genesisTxId, genesisOutputIndex } = parseSensibleId(sensibleId); let genesisUtxo = yield getLatestGenesisUtxo(proto, genesisContract.getCodeHash(), genesisTxId, genesisOutputIndex, api, address, type); if (!genesisUtxo) { throw new error_1.CodeError(error_1.ErrCode.EC_FIXED_TOKEN_SUPPLY, 'token supply is fixed'); } let txHex = yield api.getRawTxData(genesisUtxo.txId); const tx = new mvc_1.Transaction(txHex); let preTxId = tx.inputs[0].prevTxId.toString('hex'); let preOutputIndex = tx.inputs[0].outputIndex; let preTxHex = yield api.getRawTxData(preTxId); genesisUtxo.satotxInfo = { txId: genesisUtxo.txId, outputIndex: genesisUtxo.outputIndex, txHex, preTxId, preOutputIndex, preTxHex, }; let output = tx.outputs[genesisUtxo.outputIndex]; genesisUtxo.satoshis = output.satoshis; genesisUtxo.lockingScript = output.script; genesisContract.setFormatedDataPartFromLockingScript(genesisUtxo.lockingScript); return { genesisContract, genesisTxId, genesisOutputIndex, genesisUtxo, }; }); } exports.getLatestGenesisInfo = getLatestGenesisInfo; function getLatestGenesisUtxo(proto, codehash, genesisTxId, genesisOutputIndex, api, address, type) { return __awaiter(this, void 0, void 0, function* () { // 使用创世txid从接口获取该创世tx内容 let unspent; let latestGenesisTxHex = yield api.getRawTxData(genesisTxId); let latestGenesisTx = new mvc_1.Transaction(latestGenesisTxHex); // 重新构建该创世脚本 let scriptBuffer = latestGenesisTx.outputs[genesisOutputIndex].script.toBuffer(); let originGenesis = proto.getQueryGenesis(scriptBuffer); // 找回utxo let genesisUtxos; if (type === 'nft') { genesisUtxos = yield api.getNonFungibleTokenUnspents(codehash, originGenesis, address.toString()); } else { genesisUtxos = yield api.getFungibleTokenUnspents(codehash, originGenesis, address.toString()); } unspent = genesisUtxos.find((v) => v.txId == genesisTxId && v.outputIndex == genesisOutputIndex); if (!unspent) { let _dataPartObj = proto.parseDataPart(scriptBuffer); _dataPartObj.sensibleID = { txid: genesisTxId, index: genesisOutputIndex, }; let newScriptBuf = proto.updateScript(scriptBuffer, _dataPartObj); let issueGenesis = proto.getQueryGenesis(newScriptBuf); let issueUtxos; if (type === 'nft') { issueUtxos = yield api.getNonFungibleTokenUnspents(codehash, issueGenesis, address.toString()); } else { issueUtxos = yield api.getFungibleTokenUnspents(codehash, issueGenesis, address.toString()); } if (issueUtxos.length > 0) { unspent = issueUtxos[0]; } } if (unspent) { return { txId: unspent.txId, outputIndex: unspent.outputIndex, }; } }); } function parseSensibleId(sensibleId) { let sensibleIDBuf = Buffer.from(sensibleId, 'hex'); let genesisTxId = sensibleIDBuf.slice(0, 32).reverse().toString('hex'); let genesisOutputIndex = sensibleIDBuf.readUIntLE(32, 4); return { genesisTxId, genesisOutputIndex, }; } exports.parseSensibleId = parseSensibleId;