import "node_modules/scrypt-ord/src/contracts/ordinal.scrypt";import "../node_modules/scrypt-ts-lib/artifacts/merklePath.scrypt";import "../node_modules/scrypt-ts-lib/artifacts/blockchain.scrypt";import "txParserBTC.scrypt";import "merkleTreiTree.scrypt"; struct __scrypt_ts_Change { int amount; Ripemd160 address;} contract WrappedBTC { @state bytes id; const int max; const int dec; const bytes sym; @state int supply; PubKey adminPubKey; @state Sha256[2] hashes; @state bytes txIdsRoot; @state int mining_difficulty; @state int block_height; int minimal_mining_difficulty; bytes __scrypt_ts_ctx_hashoutputs; bytes __scrypt_ts_ctx_outpoint_txid; int __scrypt_ts_ctx_outpoint_outputindex; __scrypt_ts_Change __scrypt_ts_change; constructor(bytes sym, int max, int dec, Sha256[2] hashes, PubKey adminPubKey, int mining_difficulty, int minimal_mining_difficulty, int block_height) { this.max = max; this.dec = dec; this.id = b''; this.sym = sym; require(this.max <= 18446744073709551615); require(this.dec <= 18); this.supply = max; this.hashes = hashes; this.adminPubKey = adminPubKey; this.mining_difficulty = mining_difficulty; this.minimal_mining_difficulty = minimal_mining_difficulty; this.block_height = block_height; this.txIdsRoot = b'072d02306e9bd6a2afd32c04dbe136b72da3b941'; } function buildStateOutputFT(int amt) : bytes { if(this.isGenesis()) { this.initId(); } bytes stateScript = WrappedBTC.createTransferInsciption(this.id, amt) + Ordinal.removeInsciption(this.getStateScript()); return Utils.buildOutput(stateScript, 1); } function isGenesis() : bool { return this.id == b''; } static function buildTransferOutput(Ripemd160 address, bytes id, int amt) : bytes { bytes transferScript = WrappedBTC.buildTransferScript(address, id, amt); return Utils.buildOutput(transferScript, 1); } static function buildTransferScript(Ripemd160 address, bytes id, int amt) : bytes { return (WrappedBTC.createTransferInsciption(id, amt) + Utils.buildPublicKeyHashScript(address)); } static function createTransferInsciption(bytes id, int amt) : bytes { bytes amtByteString = Ordinal.int2Str(amt); bytes transferJSON = "{\"p\":\"bsv-20\",\"op\":\"transfer\",\"id\":\"" + id + "\",\"amt\":\"" + amtByteString + "\"}"; return Ordinal.createInsciption(transferJSON, "application/bsv-20"); } function initId() : bool { this.id = Ordinal.txId2str(this.__scrypt_ts_ctx_outpoint_txid) + "_" + Ordinal.int2Str(this.__scrypt_ts_ctx_outpoint_outputindex); return true; } public function mint(bytes rawTx, Ripemd160 recipient, bytes merkleTreiTreePath, Node[32] merkleProof, BlockHeader bh, SigHashPreimage __scrypt_ts_txPreimage, int __scrypt_ts_changeAmount, Ripemd160 __scrypt_ts_changeAddress) { require(Tx.checkPreimageSigHashType(__scrypt_ts_txPreimage, SigHashType(b'41'))); this.__scrypt_ts_ctx_hashoutputs = SigHash.hashOutputs(__scrypt_ts_txPreimage); this.__scrypt_ts_ctx_outpoint_outputindex = unpack(SigHash.outpoint(__scrypt_ts_txPreimage)[32 :]); this.__scrypt_ts_ctx_outpoint_txid = SigHash.outpoint(__scrypt_ts_txPreimage)[0:32]; this.__scrypt_ts_change = {__scrypt_ts_changeAmount, __scrypt_ts_changeAddress}; TxParserBTC txParser = new TxParserBTC(rawTx); BTCResult result = txParser.parse(5, 5, this.hashes); require(Blockchain.verifyBlockHeader(bh)); require(Blockchain.blockHeaderHashAsInt(bh) <= this.mining_difficulty); require(Blockchain.txInBlock(Sha256(result.txId), bh, merkleProof, 32)); this.txIdsRoot = MerkleTreiTree.addTxid(result.txId, this.txIdsRoot, merkleTreiTreePath); require(result.amt > 0); this.supply -= result.amt; require(this.supply >= 0); bytes outputs = b''; if(this.supply > 0) { outputs += this.buildStateOutputFT(this.supply); } outputs += WrappedBTC.buildTransferOutput(recipient, this.id, result.amt); outputs += this.buildChangeOutput(); require(hash256(outputs) == this.__scrypt_ts_ctx_hashoutputs); } public function updateMiningDifficulty(Sig sig, BlockHeader bh, bytes coinbaseTx, Node[32] merkleProof, SigHashPreimage __scrypt_ts_txPreimage, int __scrypt_ts_changeAmount, Ripemd160 __scrypt_ts_changeAddress) { require(Tx.checkPreimageSigHashType(__scrypt_ts_txPreimage, SigHashType(b'41'))); this.__scrypt_ts_ctx_hashoutputs = SigHash.hashOutputs(__scrypt_ts_txPreimage); this.__scrypt_ts_ctx_outpoint_outputindex = unpack(SigHash.outpoint(__scrypt_ts_txPreimage)[32 :]); this.__scrypt_ts_ctx_outpoint_txid = SigHash.outpoint(__scrypt_ts_txPreimage)[0:32]; this.__scrypt_ts_change = {__scrypt_ts_changeAmount, __scrypt_ts_changeAddress}; require(checkSig(sig, this.adminPubKey)); require(Blockchain.verifyBlockHeader(bh)); TxParserBTC txParser = new TxParserBTC(coinbaseTx); BTCResult result = txParser.parse(1, 5, this.hashes); require(txParser.isCoinbase()); int block_height = txParser.readBlockHeight(); require(block_height > this.block_height); require(Blockchain.txInBlock(Sha256(result.txId), bh, merkleProof, 32)); int new_mining_difficulty = Blockchain.bits2Target(bh.bits); require(new_mining_difficulty < this.minimal_mining_difficulty); this.mining_difficulty = new_mining_difficulty; this.block_height = block_height; bytes outputs = this.buildStateOutputFT(this.supply); outputs += this.buildChangeOutput(); require(hash256(outputs) == this.__scrypt_ts_ctx_hashoutputs); } public function updateHashes(Sig sig, Sha256[2] hashes, SigHashPreimage __scrypt_ts_txPreimage, int __scrypt_ts_changeAmount, Ripemd160 __scrypt_ts_changeAddress) { require(Tx.checkPreimageSigHashType(__scrypt_ts_txPreimage, SigHashType(b'41'))); this.__scrypt_ts_ctx_hashoutputs = SigHash.hashOutputs(__scrypt_ts_txPreimage); this.__scrypt_ts_ctx_outpoint_outputindex = unpack(SigHash.outpoint(__scrypt_ts_txPreimage)[32 :]); this.__scrypt_ts_ctx_outpoint_txid = SigHash.outpoint(__scrypt_ts_txPreimage)[0:32]; this.__scrypt_ts_change = {__scrypt_ts_changeAmount, __scrypt_ts_changeAddress}; require(checkSig(sig, this.adminPubKey)); this.hashes = hashes; bytes outputs = this.buildStateOutputFT(this.supply); outputs += this.buildChangeOutput(); require(hash256(outputs) == this.__scrypt_ts_ctx_hashoutputs); } function buildStateOutput(int amount) : bytes { return Utils.buildOutput(this.getStateScript(), amount);} function buildChangeOutput() : bytes { return this.__scrypt_ts_change.amount > 0 ? Utils.buildOutput(Utils.buildPublicKeyHashScript(this.__scrypt_ts_change.address), this.__scrypt_ts_change.amount) : b'';} }