scryptlib
Advanced tools
Comparing version 0.2.13 to 0.2.14
# CHANGELOG | ||
## 0.2.14 | ||
* support empty bytes | ||
## 0.2.13 | ||
@@ -4,0 +8,0 @@ |
export { buildContractClass, VerifyResult } from './contract'; | ||
export { compile } from './compilerWrapper'; | ||
export { bsv, signTx, toHex, getPreimage, num2bin } from './utils'; | ||
export { serializeState, State } from './serializer'; | ||
export { bsv, signTx, toHex, getPreimage, num2bin, bin2num } from './utils'; | ||
export { serializeState, deserializeState, State, STATE_LEN_2BYTES, STATE_LEN_4BYTES } from './serializer'; | ||
export { Int, Bool, Bytes, PrivKey, PubKey, Sig, Ripemd160, Sha1, Sha256, SigHashType, SigHashPreimage, OpCodeType } from './scryptTypes'; |
@@ -13,4 +13,8 @@ "use strict"; | ||
Object.defineProperty(exports, "num2bin", { enumerable: true, get: function () { return utils_1.num2bin; } }); | ||
Object.defineProperty(exports, "bin2num", { enumerable: true, get: function () { return utils_1.bin2num; } }); | ||
var serializer_1 = require("./serializer"); | ||
Object.defineProperty(exports, "serializeState", { enumerable: true, get: function () { return serializer_1.serializeState; } }); | ||
Object.defineProperty(exports, "deserializeState", { enumerable: true, get: function () { return serializer_1.deserializeState; } }); | ||
Object.defineProperty(exports, "STATE_LEN_2BYTES", { enumerable: true, get: function () { return serializer_1.STATE_LEN_2BYTES; } }); | ||
Object.defineProperty(exports, "STATE_LEN_4BYTES", { enumerable: true, get: function () { return serializer_1.STATE_LEN_4BYTES; } }); | ||
var scryptTypes_1 = require("./scryptTypes"); | ||
@@ -17,0 +21,0 @@ Object.defineProperty(exports, "Int", { enumerable: true, get: function () { return scryptTypes_1.Int; } }); |
@@ -0,3 +1,18 @@ | ||
import { bsv } from './utils'; | ||
export declare const STATE_LEN_2BYTES = 2; | ||
export declare const STATE_LEN_4BYTES = 4; | ||
export declare type State = Record<string, boolean | number | bigint | string>; | ||
export declare type StateArray = Array<boolean | number | bigint | string>; | ||
export declare function serializeState(state: State | StateArray, stateBytes?: number): string; | ||
export declare function serializeState(state: State | StateArray, stateBytes?: number, schema?: State | StateArray): string; | ||
declare class OpState { | ||
op: any; | ||
constructor(op: any); | ||
toNumber(): number; | ||
toBigInt(): bigint; | ||
toBoolean(): boolean; | ||
toHex(): string; | ||
toString(arg?: string): any; | ||
} | ||
export declare type OpStateArray = Array<OpState>; | ||
export declare function deserializeState(s: string | bsv.Script, schema?: State | StateArray): OpStateArray | State | StateArray; | ||
export {}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.serializeState = void 0; | ||
exports.deserializeState = exports.serializeState = exports.STATE_LEN_4BYTES = exports.STATE_LEN_2BYTES = void 0; | ||
const utils_1 = require("./utils"); | ||
/* | ||
* a varint serializer into Script ASM | ||
*/ | ||
const Script = utils_1.bsv.Script; | ||
const Opcode = utils_1.bsv.Opcode; | ||
const BN = utils_1.bsv.crypto.BN; | ||
// number of bytes to denote state length after serialization, exclusing varint prefix | ||
const STATE_LEN = 2; | ||
exports.STATE_LEN_2BYTES = 2; | ||
exports.STATE_LEN_4BYTES = 4; | ||
function serializeBool(flag) { | ||
@@ -16,10 +15,12 @@ return flag ? 'OP_TRUE' : 'OP_FALSE'; | ||
function serializeInt(n) { | ||
// special case: otherwise it returns empty string | ||
// use "==" not "===" since "0n === 0" returns false | ||
if (n == 0) { | ||
const num = new BN(n); | ||
if (num.eqn(0)) { | ||
return '00'; | ||
} | ||
const num = new BN(n); | ||
return num.toSM({ endian: 'little' }).toString('hex'); | ||
} | ||
function serializeString(str) { | ||
const buf = Buffer.from(str, 'utf8'); | ||
return buf.toString('hex'); | ||
} | ||
// TODO: validate | ||
@@ -29,2 +30,20 @@ function serializeBytes(hexStr) { | ||
} | ||
function serializeWithSchema(state, key, schema = undefined) { | ||
const type = schema[key]; | ||
if (type === 'boolean') { | ||
return serializeBool(state[key]); | ||
} | ||
else if (type === 'number') { | ||
return serializeInt(state[key]); | ||
} | ||
else if (type === 'bigint') { | ||
return serializeInt(state[key]); | ||
} | ||
else if (type === 'string') { | ||
return serializeString(state[key]); | ||
} | ||
else { | ||
return serializeBytes(state[key]); | ||
} | ||
} | ||
function serialize(x) { | ||
@@ -45,8 +64,15 @@ if (typeof x === 'boolean') { | ||
// serialize contract state into Script ASM | ||
function serializeState(state, stateBytes = STATE_LEN) { | ||
function serializeState(state, stateBytes = exports.STATE_LEN_2BYTES, schema = undefined) { | ||
const asms = []; | ||
Object.values(state).forEach(s => { | ||
const str = serialize(s); | ||
asms.push(str); | ||
}); | ||
const keys = Object.keys(state); | ||
for (const key of keys) { | ||
if (schema) { | ||
const str = serializeWithSchema(state, key, schema); | ||
asms.push(str); | ||
} | ||
else { | ||
const str = serialize(state[key]); | ||
asms.push(str); | ||
} | ||
} | ||
const script = Script.fromASM(asms.join(' ')); | ||
@@ -60,2 +86,103 @@ const scriptHex = script.toHex(); | ||
exports.serializeState = serializeState; | ||
class OpState { | ||
constructor(op) { | ||
this.op = op; | ||
} | ||
toNumber() { | ||
return Number(this.toBigInt()); | ||
} | ||
toBigInt() { | ||
if (this.op.opcodenum === Opcode.OP_1) { | ||
return 1n; | ||
} | ||
else if (this.op.opcodenum === Opcode.OP_0) { | ||
return 0n; | ||
} | ||
else if (this.op.opcodenum === Opcode.OP_1NEGATE) { | ||
return -1n; | ||
} | ||
else if (this.op.opcodenum >= Opcode.OP_2 && this.op.opcodenum <= Opcode.OP_16) { | ||
return BigInt(this.op.opcodenum - Opcode.OP_2 + 2); | ||
} | ||
else { | ||
if (!this.op.buf) | ||
throw new Error('state does not have a number representation'); | ||
return utils_1.bin2num(this.op.buf); | ||
} | ||
} | ||
toBoolean() { | ||
return this.toBigInt() !== 0n; | ||
} | ||
toHex() { | ||
if (!this.op.buf) | ||
throw new Error('state does not have a hexadecimal representation'); | ||
return this.op.buf.toString('hex'); | ||
} | ||
toString(arg = 'utf8') { | ||
if (!this.op.buf) { | ||
throw new Error('state does not have a string representation'); | ||
} | ||
return this.op.buf.toString(arg).trim(); | ||
} | ||
} | ||
// deserialize Script or Script Hex or Script ASM Code to contract state array and object | ||
function deserializeState(s, schema = undefined) { | ||
let script; | ||
try { | ||
script = new Script(s); | ||
} | ||
catch (e) { | ||
script = Script.fromASM(s); | ||
} | ||
const chunks = script.chunks; | ||
const states = []; | ||
const pos = chunks.length; | ||
//the last opcode is length of stats, skip | ||
for (let i = pos - 2; i >= 0; i--) { | ||
const opcodenum = chunks[i].opcodenum; | ||
if (opcodenum === Opcode.OP_RETURN) { | ||
break; | ||
} | ||
else { | ||
states.unshift(new OpState(chunks[i])); | ||
} | ||
} | ||
//deserialize to an array | ||
if (!schema) { | ||
return states; | ||
} | ||
//deserialize to an object | ||
let ret; | ||
if (Array.isArray(schema)) { | ||
ret = []; | ||
} | ||
else { | ||
ret = {}; | ||
} | ||
const keys = Object.keys(schema); | ||
for (let i = 0; i < states.length; i++) { | ||
const key = keys[i]; | ||
if (!key) { | ||
break; | ||
} | ||
const val = schema[key]; | ||
if (val === 'boolean' || typeof val === 'boolean') { | ||
ret[key] = states[i].toBoolean(); | ||
} | ||
else if (val === 'number' || typeof val === 'number') { | ||
ret[key] = states[i].toNumber(); | ||
} | ||
else if (val === 'bigint' || typeof val === 'bigint') { | ||
ret[key] = states[i].toBigInt(); | ||
} | ||
else if (val === 'string') { | ||
ret[key] = states[i].toString(); | ||
} | ||
else { | ||
ret[key] = states[i].toHex(); | ||
} | ||
} | ||
return ret; | ||
} | ||
exports.deserializeState = deserializeState; | ||
//# sourceMappingURL=serializer.js.map |
@@ -68,5 +68,6 @@ "use strict"; | ||
// bytes | ||
let m = /^b'([\da-fA-F]+)'$/.exec(l); | ||
// note: special handling of empty bytes b'' | ||
let m = /^b'([\da-fA-F]*)'$/.exec(l); | ||
if (m) { | ||
return [getValidatedHexString(m[1]), 'bytes']; | ||
return [m[1].length > 0 ? getValidatedHexString(m[1]) : 'OP_0', 'bytes']; | ||
} | ||
@@ -124,3 +125,3 @@ // PrivKey | ||
} | ||
throw new Error(`<${l}> can't be casted to asm format, only support sCrypt native types`); | ||
throw new Error(`<${l}> cannot be cast to ASM format, only sCrypt native types supported`); | ||
} | ||
@@ -127,0 +128,0 @@ exports.literal2Asm = literal2Asm; |
{ | ||
"name": "scryptlib", | ||
"version": "0.2.13", | ||
"version": "0.2.14", | ||
"description": "Javascript SDK for integration of Bitcoin SV Smart Contracts written in sCrypt language.", | ||
@@ -5,0 +5,0 @@ "engines": { |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
67391
1530