UNPKG

scryptlib

Version:

Javascript SDK for integration of Bitcoin SV Smart Contracts written in sCrypt language.

243 lines 10 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const _1 = require("."); const deserializer_1 = require("./deserializer"); const internal_1 = require("./internal"); const scryptTypes_1 = require("./scryptTypes"); class Stateful { static int2hex(n) { let asm = ''; const num = new _1.bsv.crypto.BN(n); if (num.eqn(0)) { asm = '00'; } else { asm = num.toSM({ endian: 'little' }).toString('hex'); } return _1.bsv.Script.fromASM(asm).toHex(); } static hex2int(hex) { const s = _1.bsv.Script.fromHex(hex); const chuck = s.chunks[0]; return (0, _1.bin2num)(chuck.buf.toString('hex')); } static bool2hex(b) { if (b) { return '01'; } return '00'; } static hex2bool(hex) { if (hex === '01') { return true; } else if (hex === '00') { return false; } throw new Error(`invalid hex ${hex}`); } static bytes2hex(b) { if (b === '') { return '00'; } return _1.bsv.Script.fromASM(b).toHex(); } static hex2bytes(hex) { if (hex === '00') { return ''; } const s = _1.bsv.Script.fromHex(hex); const chuck = s.chunks[0]; return chuck.buf.toString('hex'); } static toHex(x, type) { if (type === scryptTypes_1.ScryptType.INT || type === scryptTypes_1.ScryptType.PRIVKEY) { return Stateful.int2hex(x); } else if (type === scryptTypes_1.ScryptType.BOOL) { return Stateful.bool2hex(x); } else if ((0, scryptTypes_1.isBytes)(type)) { return Stateful.bytes2hex(x); } throw new Error(`unsupported type: ${type}`); } static serialize(x, type) { if (type === scryptTypes_1.ScryptType.INT || type === scryptTypes_1.ScryptType.PRIVKEY) { const num = new _1.bsv.crypto.BN(x); if (num.eqn(0)) { return ''; } else { return num.toSM({ endian: 'little' }).toString('hex'); } } else if (type === scryptTypes_1.ScryptType.BOOL) { if (x) { return '01'; } return ''; } else if ((0, scryptTypes_1.isBytes)(type)) { return x; } throw new Error(`unsupported type: ${type}`); } /** * only used for state contract * @param args * @param isGenesis * @param finalTypeResolver * @returns */ static buildState(args, isGenesis, resolver) { const args_ = args.map(arg => { return (0, internal_1.flatternArg)(arg, resolver, { state: true, ignoreValue: false }); }).flat(Infinity); if (args_.length <= 0) { throw new Error('no state property found, buildContractState only used for state contract'); } // append isGenesis which is a hidden built-in state let state_hex = `${Stateful.toHex(isGenesis, scryptTypes_1.ScryptType.BOOL)}`; state_hex += args_.map(a => Stateful.toHex(a.value, a.type)).join(''); //append meta if (state_hex) { const state_len = state_hex.length / 2; state_hex += (0, _1.num2bin)(BigInt(state_len), 4) + (0, _1.num2bin)(Stateful.CURRENT_STATE_VERSION, 1); return state_hex; } return state_hex; } static buildDefaultStateArgs(contract) { const dummyArgs = contract.stateProps.map(p => { const dummyArg = Object.assign({}, p, { value: false }); return (0, internal_1.flatternArg)(dummyArg, contract.resolver, { state: true, ignoreValue: true }); }).flat(Infinity); const hexTemplateMap = new Map(); dummyArgs.forEach(p => { if (p.type === scryptTypes_1.ScryptType.INT || p.type === scryptTypes_1.ScryptType.PRIVKEY) { hexTemplateMap.set(`<${p.name}>`, Stateful.int2hex((0, scryptTypes_1.Int)(0))); } else if (p.type === scryptTypes_1.ScryptType.BOOL) { hexTemplateMap.set(`<${p.name}>`, Stateful.bool2hex(true)); } else if (p.type === scryptTypes_1.ScryptType.BYTES || p.type === scryptTypes_1.ScryptType.PUBKEY || p.type === scryptTypes_1.ScryptType.SIG || p.type === scryptTypes_1.ScryptType.RIPEMD160 || p.type === scryptTypes_1.ScryptType.SHA1 || p.type === scryptTypes_1.ScryptType.SHA256 || p.type === scryptTypes_1.ScryptType.SIGHASHTYPE || p.type === scryptTypes_1.ScryptType.SIGHASHPREIMAGE || p.type === scryptTypes_1.ScryptType.OPCODETYPE) { hexTemplateMap.set(`<${p.name}>`, Stateful.bytes2hex('00')); } else { throw new Error(`param ${p.name} has unknown type ${p.type}`); } }); return contract.stateProps.map(param => (0, deserializer_1.deserializeArgfromHex)(contract.resolver, Object.assign(param, { value: undefined }), hexTemplateMap, { state: true })); } static deserializer(type, hex) { switch (type) { case scryptTypes_1.ScryptType.BOOL: return (0, scryptTypes_1.Bool)(Stateful.hex2bool(hex)); case scryptTypes_1.ScryptType.INT: return (0, scryptTypes_1.Int)(Stateful.hex2int(hex)); case scryptTypes_1.ScryptType.BYTES: return (0, scryptTypes_1.Bytes)(Stateful.hex2bytes(hex)); case scryptTypes_1.ScryptType.PRIVKEY: return (0, scryptTypes_1.PrivKey)(Stateful.hex2int(hex)); case scryptTypes_1.ScryptType.PUBKEY: return (0, scryptTypes_1.PubKey)(Stateful.hex2bytes(hex)); case scryptTypes_1.ScryptType.SIG: return (0, scryptTypes_1.Sig)(Stateful.hex2bytes(hex)); case scryptTypes_1.ScryptType.RIPEMD160: return (0, scryptTypes_1.Ripemd160)(Stateful.hex2bytes(hex)); case scryptTypes_1.ScryptType.SHA1: return (0, scryptTypes_1.Sha1)(Stateful.hex2bytes(hex)); case scryptTypes_1.ScryptType.SHA256: return (0, scryptTypes_1.Sha256)(Stateful.hex2bytes(hex)); case scryptTypes_1.ScryptType.SIGHASHTYPE: return (0, scryptTypes_1.SigHashType)(Number(Stateful.hex2int(hex))); case scryptTypes_1.ScryptType.SIGHASHPREIMAGE: return (0, scryptTypes_1.SigHashPreimage)(Stateful.hex2bytes(hex)); case scryptTypes_1.ScryptType.OPCODETYPE: return (0, scryptTypes_1.OpCodeType)(Stateful.hex2bytes(hex)); default: throw new Error(`<${type}> cannot be cast to ScryptType, only sCrypt native types supported`); } } static readBytes(br) { try { const opcodenum = br.readUInt8(); let len, data; if (opcodenum == 0) { data = ''; } else if (opcodenum > 0 && opcodenum < _1.bsv.Opcode.OP_PUSHDATA1) { len = opcodenum; data = br.read(len).toString('hex'); } else if (opcodenum === _1.bsv.Opcode.OP_PUSHDATA1) { len = br.readUInt8(); data = br.read(len).toString('hex'); } else if (opcodenum === _1.bsv.Opcode.OP_PUSHDATA2) { len = br.readUInt16LE(); data = br.read(len).toString('hex'); } else if (opcodenum === _1.bsv.Opcode.OP_PUSHDATA4) { len = br.readUInt32LE(); data = br.read(len).toString('hex'); } else { data = (0, _1.num2bin)(BigInt(opcodenum - 80), 1); } return { data: data, opcodenum: opcodenum }; } catch (e) { throw new Error('readBytes: ' + e); } } static parseStateHex(contract, scriptHex) { const metaScript = scriptHex.substr(scriptHex.length - 10, 10); /* eslint-disable @typescript-eslint/no-unused-vars */ const version = Number((0, _1.bin2num)(metaScript.substr(metaScript.length - 2, 2))); const stateLen = Number((0, _1.bin2num)(metaScript.substr(0, 8))); const stateHex = scriptHex.substr(scriptHex.length - 10 - stateLen * 2, stateLen * 2); const br = new _1.bsv.encoding.BufferReader(Buffer.from(stateHex, 'hex')); const opcodenum = br.readUInt8(); const isGenesis = opcodenum == 1; const stateTemplateArgs = new Map(); const dummyArgs = contract.stateProps.map(p => { const dummyArg = Object.assign({}, p, { value: false }); return (0, internal_1.flatternArg)(dummyArg, contract.resolver, { state: true, ignoreValue: true }); }).flat(Infinity); dummyArgs.forEach((param) => { if (param.type === scryptTypes_1.ScryptType.BOOL) { const opcodenum = br.readUInt8(); stateTemplateArgs.set(`<${param.name}>`, opcodenum === 1 ? '01' : '00'); } else { const { data } = Stateful.readBytes(br); stateTemplateArgs.set(`<${param.name}>`, data ? _1.bsv.Script.fromASM(data).toHex() : '00'); } }); const args = contract.stateProps.map(param => Object.assign({}, param, { value: false })).map(arg => { return (0, deserializer_1.deserializeArgfromHex)(contract.resolver, arg, stateTemplateArgs, { state: true }); }); return [isGenesis, args]; } } exports.default = Stateful; // state version Stateful.CURRENT_STATE_VERSION = (0, scryptTypes_1.Int)(0); //# sourceMappingURL=stateful.js.map