Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@tact-lang/opcode

Package Overview
Dependencies
Maintainers
3
Versions
16
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@tact-lang/opcode - npm Package Compare versions

Comparing version 0.0.9 to 0.0.10

dist/utils/subcell.d.ts

8

CHANGELOG.md

@@ -8,2 +8,10 @@ # Changelog

## [0.0.10] - 2023-03-27
## Fixed
- Fix opcode offsets and source cell hash in `PUSHCONT` opcode that could lead to broken code coverage
## Changed
- Upgrade to `ton-core@0.49.0`
## [0.0.9] - 2023-03-24

@@ -10,0 +18,0 @@ - Fix oppcode length in shifted cells

6

dist/codepage/opcodes.gen.d.ts

@@ -115,6 +115,6 @@ import { Cell } from 'ton-core';

code: 'PUSHSLICE';
args: [Cell];
args: [Cell, number, number, number, number];
} | {
code: 'PUSHCONT';
args: [Cell];
args: [Cell, number, number, number, number];
} | {

@@ -185,3 +185,3 @@ code: 'ADDCONST';

code: 'STSLICECONST';
args: [Cell];
args: [Cell, number, number, number, number];
} | {

@@ -188,0 +188,0 @@ code: 'LDI';

@@ -6,10 +6,2 @@ "use strict";

const Codepage_1 = require("./Codepage");
function fetchSubslice(slice, bits, refs) {
let b = (0, ton_core_1.beginCell)()
.storeBits(slice.loadBits(bits));
for (let i = 0; i < (refs || 0); i++) {
b.storeRef(slice.loadRef());
}
return b.asCell();
}
const CP0Auto = new Codepage_1.Codepage();

@@ -286,17 +278,24 @@ exports.CP0Auto = CP0Auto;

let x = slice.loadUint(4);
let len = 8 * x + 4;
let subslice = fetchSubslice(slice, len);
return { code: 'PUSHSLICE', args: [subslice] };
let bits = 8 * x + 4;
let refs = 0;
let bitsOffset = slice.offsetBits;
let refsOffset = slice.offsetRefs;
let cell = loadSubslice(slice, bits, refs);
return { code: 'PUSHSLICE', args: [cell, bitsOffset, refsOffset, bits, refs] };
});
CP0Auto.insertHex('8c', 8, (slice) => {
let r = slice.loadUint(2) + 1;
let xx = slice.loadUint(5);
let subslice = fetchSubslice(slice, 8 * xx + 1, r);
return { code: 'PUSHSLICE', args: [subslice] };
let refs = slice.loadUint(2) + 1;
let bits = (8 * slice.loadUint(5) + 1);
let bitsOffset = slice.offsetBits;
let refsOffset = slice.offsetRefs;
let cell = loadSubslice(slice, bits, refs);
return { code: 'PUSHSLICE', args: [cell, bitsOffset, refsOffset, bits, refs] };
});
CP0Auto.insertHex('8d', 8, (slice) => {
let r = slice.loadUint(3);
let xx = slice.loadUint(7);
let subslice = fetchSubslice(slice, 8 * xx + 6, r);
return { code: 'PUSHSLICE', args: [subslice] };
let refs = slice.loadUint(3);
let bits = 8 * slice.loadUint(7) + 6;
let bitsOffset = slice.offsetBits;
let refsOffset = slice.offsetRefs;
let cell = loadSubslice(slice, bits, refs);
return { code: 'PUSHSLICE', args: [cell, bitsOffset, refsOffset, bits, refs] };
});

@@ -307,10 +306,15 @@ // 9281536 (DUMMY)

let refs = (args >> 7) & 3;
let dataBytes = (args & 127) * 8;
let subslice = fetchSubslice(slice, dataBytes, refs);
return { code: 'PUSHCONT', args: [subslice] };
let bits = (args & 127) * 8;
let bitsOffset = slice.offsetBits;
let refsOffset = slice.offsetRefs;
let cell = loadSubslice(slice, bits, refs);
return { code: 'PUSHCONT', args: [cell, bitsOffset, refsOffset, bits, refs] };
});
CP0Auto.insertHex('9', 4, (slice) => {
let len = slice.loadUint(4) * 8;
let subslice = fetchSubslice(slice, len);
return { code: 'PUSHCONT', args: [subslice] };
let bits = slice.loadUint(4) * 8;
let refs = 0;
let bitsOffset = slice.offsetBits;
let refsOffset = slice.offsetRefs;
let cell = loadSubslice(slice, bits, refs);
return { code: 'PUSHCONT', args: [cell, bitsOffset, refsOffset, bits, refs] };
});

@@ -540,5 +544,7 @@ CP0Auto.insertHex('a0', 8, { code: 'ADD' });

let refs = slice.loadUint(2);
let dataBits = slice.loadUint(3) * 8 + 1;
let subslice = fetchSubslice(slice, dataBits, refs);
return { code: `STSLICECONST`, args: [subslice] };
let bits = slice.loadUint(3) * 8 + 1;
let bitsOffset = slice.offsetBits;
let refsOffset = slice.offsetRefs;
let cell = loadSubslice(slice, bits, refs);
return { code: `STSLICECONST`, args: [cell, bitsOffset, refsOffset, bits, refs] };
});

@@ -1168,1 +1174,12 @@ CP0Auto.insertHex('d0', 8, { code: 'CTOS' });

});
//
// Utils
//
function loadSubslice(slice, bits, refs) {
let b = (0, ton_core_1.beginCell)()
.storeBits(slice.loadBits(bits));
for (let i = 0; i < (refs || 0); i++) {
b.storeRef(slice.loadRef());
}
return b.asCell();
}

@@ -75,2 +75,8 @@ "use strict";

}
// Slices
if (op.code === 'PUSHSLICE'
|| op.code === 'PUSHCONT'
|| op.code === 'STSLICECONST') {
return `${op.args[0]} ${op.code}`;
}
// Debug

@@ -77,0 +83,0 @@ if (op.code === 'DEBUG') {

@@ -12,7 +12,7 @@ "use strict";

const printer = args.printer;
const hash = args.src.hash().toString('hex');
const writer = args.writer;
const opcodes = (0, decompiler_1.decompile)({
src: args.src,
srcOffset: args.srcOffset,
offset: args.offset,
limit: args.limit,
allowUnknown: false

@@ -33,3 +33,3 @@ });

let callRefs = new Map();
function extract(cell) {
function extractCallRef(cell) {
// Check if we have a call ref

@@ -49,6 +49,7 @@ let k = cell.hash().toString('hex');

src: cell,
srcOffset: 0,
offset: { bits: 0, refs: 0 },
limit: null,
root: false,
writer: w,
callRefExtractor: extract,
callRefExtractor: extractCallRef,
printer: args.printer

@@ -68,6 +69,7 @@ });

src: value.cell,
srcOffset: value.offset,
offset: { bits: value.offset, refs: 0 },
limit: null,
root: false,
writer: w,
callRefExtractor: extract,
callRefExtractor: extractCallRef,
printer: args.printer

@@ -93,3 +95,3 @@ });

let opstr = `${key} ${value.ref ? 'PROCREF' : 'PROC'}:<{`;
writer.append(printer({ op: opstr, offset: value.srcOffset, length: 0, hash, cell: value.src }, writer.indent));
writer.append(printer({ op: opstr, offset: value.srcOffset, length: 0, hash }, writer.indent));
writer.inIndent(() => {

@@ -101,3 +103,3 @@ value.rendered.split('\n').forEach(line => {

opstr = `}>`;
writer.append(printer({ op: opstr, offset: value.srcOffset, length: 0, hash, cell: value.src }, writer.indent));
writer.append(printer({ op: opstr, offset: value.srcOffset, length: 0, hash }, writer.indent));
}

@@ -110,23 +112,46 @@ });

for (const op of opcodes) {
const opcode = op.op;
// Special cases for call refs
if (op.op.code === 'CALLREF' && args.callRefExtractor) {
let id = args.callRefExtractor(op.op.args[0]);
if (opcode.code === 'CALLREF' && args.callRefExtractor) {
let id = args.callRefExtractor(opcode.args[0]);
let opstr = `${id} INLINECALLDICT`;
writer.append(printer({ op: opstr, offset: op.offset, length: op.length, hash, cell: args.src }, writer.indent));
writer.append(printer({ op: opstr, offset: op.offset, length: op.length, hash: op.hash }, writer.indent));
continue;
}
// Special case for PUSHCONT
if (opcode.code === 'PUSHCONT') {
let opstr = '<{';
writer.append(printer({ op: opstr, offset: op.offset, length: op.length, hash: op.hash }, writer.indent));
writer.inIndent(() => {
decompileCell({
src: args.src,
offset: { bits: opcode.args[1], refs: opcode.args[2] },
limit: { bits: opcode.args[3], refs: opcode.args[4] },
root: false,
writer: writer,
callRefExtractor: args.callRefExtractor,
printer: args.printer
});
});
opstr = '}> ' + op.op.code;
writer.append(printer({ op: opstr, offset: op.offset, length: op.length, hash: op.hash }, writer.indent));
continue;
}
// Special cases for continuations
if (op.op.code === 'PUSHCONT'
|| op.op.code === 'IFREFELSE'
|| op.op.code === 'CALLREF'
|| op.op.code === 'IFJMPREF'
|| op.op.code === 'IFREF'
|| op.op.code === 'IFREFELSEREF') {
let c = op.op.args[0];
if (opcode.code === 'IFREFELSE'
|| opcode.code === 'CALLREF'
|| opcode.code === 'IFJMPREF'
|| opcode.code === 'IFREF'
|| opcode.code === 'IFNOTREF'
|| opcode.code === 'IFNOTJMPREF'
|| opcode.code === 'IFREFELSEREF'
|| opcode.code === 'IFELSEREF') {
let c = opcode.args[0];
let opstr = '<{';
writer.append(printer({ op: opstr, offset: op.offset, length: op.length, hash, cell: args.src }, writer.indent));
writer.append(printer({ op: opstr, offset: op.offset, length: op.length, hash: op.hash }, writer.indent));
writer.inIndent(() => {
decompileCell({
src: c,
srcOffset: 0,
offset: { bits: 0, refs: 0 },
limit: null,
root: false,

@@ -138,14 +163,14 @@ writer: writer,

});
opstr = '}> ' + op.op.code;
writer.append(printer({ op: opstr, offset: op.offset, length: op.length, hash, cell: args.src }, writer.indent));
opstr = '}> ' + opcode.code;
writer.append(printer({ op: opstr, offset: op.offset, length: op.length, hash: op.hash }, writer.indent));
continue;
}
// Special cases for unknown opcode
if (op.op.code === 'unknown') {
writer.append('!' + op.op.data.toString());
if (opcode.code === 'unknown') {
writer.append('!' + opcode.data.toString());
continue;
}
// All remaining opcodes
let opstr = (0, opcodeToString_1.opcodeToString)(op.op);
writer.append(printer({ op: opstr, offset: op.offset, length: op.length, hash, cell: args.src }, writer.indent));
let opstr = (0, opcodeToString_1.opcodeToString)(opcode);
writer.append(printer({ op: opstr, offset: op.offset, length: op.length, hash: op.hash }, writer.indent));
}

@@ -165,3 +190,4 @@ }

src,
srcOffset: 0,
offset: { bits: 0, refs: 0 },
limit: null,
root: true,

@@ -180,14 +206,7 @@ writer,

parse: (src) => {
let bitsReader = src._reader.clone();
let offset = bitsReader._offset;
bitsReader.reset();
let bits = bitsReader.loadBits(bitsReader.remaining);
let b = (0, ton_core_1.beginCell)()
.storeBits(bits);
while (src.remainingRefs > 0) {
b.storeRef(src.loadRef());
}
return { offset, cell: b.endCell() };
let cloned = src.clone(true);
let offset = src.offsetBits;
return { offset, cell: cloned.asCell() };
}
};
}
/// <reference types="node" />
import { Cell, Slice } from "ton-core";
import { Cell } from "ton-core";
import { OpCode } from "../codepage/opcodes.gen";

@@ -11,2 +11,3 @@ import { Maybe } from "../utils/maybe";

op: DecompiledOpCode;
hash: string;
offset: number;

@@ -16,5 +17,12 @@ length: number;

export declare function decompile(args: {
src: Cell | Slice | Buffer;
srcOffset?: Maybe<number>;
src: Cell | Buffer;
offset?: Maybe<{
bits: number;
refs: number;
}>;
limit?: Maybe<{
bits: number;
refs: number;
}>;
allowUnknown?: boolean;
}): DecompiledInstruction[];

@@ -6,2 +6,3 @@ "use strict";

const loadOpcode_1 = require("../codepage/loadOpcode");
const subcell_1 = require("../utils/subcell");
function decompile(args) {

@@ -11,27 +12,39 @@ // Result collection

// Load slice
let sc;
let source;
if (Buffer.isBuffer(args.src)) {
sc = ton_core_1.Cell.fromBoc(args.src)[0].beginParse();
source = ton_core_1.Cell.fromBoc(args.src)[0];
}
else if (args.src instanceof ton_core_1.Cell) {
sc = args.src.beginParse();
source = args.src;
}
else {
sc = args.src;
throw new Error('Invalid source');
}
// Hash
let hash = source.hash().toString('hex');
// Prepare offset
let sco = args.srcOffset || 0;
if (args.srcOffset && args.srcOffset > 0) {
sc.skip(args.srcOffset);
let bitsDelta = 0;
let refsDelta = 0;
if (args.offset) {
bitsDelta = args.offset.bits;
refsDelta = args.offset.refs;
}
// Prepare remaining tracker
let scl = sc.remainingBits;
while (sc.remainingBits > 0) {
// Prepare offset
let bitsLimit = args.limit ? (args.limit.bits + bitsDelta) : source.bits.length;
let refsLimit = args.limit ? (args.limit.refs + refsDelta) : source.refs.length;
let slice = (0, subcell_1.subcell)({
cell: source,
bits: bitsLimit,
refs: refsLimit
}).beginParse();
if (args.offset) {
slice.skip(args.offset.bits);
for (let i = 0; i < args.offset.refs; i++)
slice.loadRef();
}
while (slice.remainingBits > 0) {
// Load opcode
const opcode = (0, loadOpcode_1.loadOpcode)(sc);
// Update state
let currentOffset = sco; // Persisted offset before reading opcode
let currentLength = scl - sc.remainingBits; // Check difference in remaining bits to calculate opcode length
scl -= currentLength;
sco += currentLength;
const opcodeOffset = slice.offsetBits;
const opcode = (0, loadOpcode_1.loadOpcode)(slice);
const opcodeLength = slice.offsetBits - opcodeOffset;
// Failed case

@@ -44,3 +57,3 @@ if (!opcode.ok) {

}
fullCell.storeSlice(sc);
fullCell.storeSlice(slice);
result.push({

@@ -51,4 +64,5 @@ op: {

},
offset: currentOffset,
length: currentLength
hash,
offset: opcodeOffset,
length: opcodeLength
});

@@ -64,10 +78,11 @@ break;

op: opcode.read,
offset: currentOffset,
length: currentLength
hash,
offset: opcodeOffset,
length: opcodeLength
});
// Implicit jump
if (sc.remainingBits === 0 && sc.remainingRefs > 0) {
sc = sc.loadRef().beginParse();
scl = sc.remainingBits;
sco = 0;
if (slice.remainingBits === 0 && slice.remainingRefs > 0) {
let n = slice.loadRef();
hash = n.hash().toString('hex');
slice = n.beginParse();
}

@@ -74,0 +89,0 @@ }

@@ -1,6 +0,4 @@

import { Cell } from "ton-core";
export type Printer = (src: string | {
op: string;
hash: string;
cell: Cell;
offset: number;

@@ -7,0 +5,0 @@ length: number;

{
"name": "@tact-lang/opcode",
"version": "0.0.9",
"version": "0.0.10",
"main": "dist/index.js",

@@ -23,3 +23,3 @@ "repository": "https://github.com/tact-lang/ton-opcode.git",

"js-yaml": "^4.1.0",
"ton-core": "^0.48.0",
"ton-core": "^0.49.0",
"ton-crypto": "^3.2.0",

@@ -32,3 +32,3 @@ "ts-jest": "^29.0.5",

"peerDependencies": {
"ton-core": ">=0.48.0",
"ton-core": ">=0.49.0",
"ton-crypto": "^3.2.0"

@@ -35,0 +35,0 @@ },

@@ -1,2 +0,2 @@

import { Slice } from "ton-core";
import { Cell, Slice } from "ton-core";
import { CP0Auto } from "./opcodes";

@@ -3,0 +3,0 @@ import { OpCode } from "./opcodes.gen";

@@ -41,4 +41,4 @@ import { Cell } from 'ton-core';

| { code: 'PUSHREFCONT', args: [Cell] }
| { code: 'PUSHSLICE', args: [Cell] }
| { code: 'PUSHCONT', args: [Cell] }
| { code: 'PUSHSLICE', args: [Cell, number, number, number, number] }
| { code: 'PUSHCONT', args: [Cell, number, number, number, number] }
| { code: 'ADDCONST', args: [number] }

@@ -65,3 +65,3 @@ | { code: 'MULCONST', args: [number] }

| { code: 'BCHKBITSQ', args: [number] }
| { code: 'STSLICECONST', args: [Cell] }
| { code: 'STSLICECONST', args: [Cell, number, number, number, number] }
| { code: 'LDI', args: [number] }

@@ -68,0 +68,0 @@ | { code: 'LDU', args: [number] }

import { beginCell, Slice } from 'ton-core';
import { Codepage } from './Codepage';
function fetchSubslice(slice: Slice, bits: number, refs?: number) {
let b = beginCell()
.storeBits(slice.loadBits(bits));
for (let i = 0; i < (refs || 0); i++) {
b.storeRef(slice.loadRef());
}
return b.asCell();
}
const CP0Auto = new Codepage();

@@ -284,17 +275,24 @@

let x = slice.loadUint(4);
let len = 8 * x + 4;
let subslice = fetchSubslice(slice, len);
return { code: 'PUSHSLICE', args: [subslice] };
let bits = 8 * x + 4;
let refs = 0;
let bitsOffset = slice.offsetBits;
let refsOffset = slice.offsetRefs;
let cell = loadSubslice(slice, bits, refs);
return { code: 'PUSHSLICE', args: [cell, bitsOffset, refsOffset, bits, refs] };
});
CP0Auto.insertHex('8c', 8, (slice) => {
let r = slice.loadUint(2) + 1;
let xx = slice.loadUint(5);
let subslice = fetchSubslice(slice, 8 * xx + 1, r);
return { code: 'PUSHSLICE', args: [subslice] };
let refs = slice.loadUint(2) + 1;
let bits = (8 * slice.loadUint(5) + 1);
let bitsOffset = slice.offsetBits;
let refsOffset = slice.offsetRefs;
let cell = loadSubslice(slice, bits, refs);
return { code: 'PUSHSLICE', args: [cell, bitsOffset, refsOffset, bits, refs] };
});
CP0Auto.insertHex('8d', 8, (slice) => {
let r = slice.loadUint(3);
let xx = slice.loadUint(7);
let subslice = fetchSubslice(slice, 8 * xx + 6, r);
return { code: 'PUSHSLICE', args: [subslice] };
let refs = slice.loadUint(3);
let bits = 8 * slice.loadUint(7) + 6;
let bitsOffset = slice.offsetBits;
let refsOffset = slice.offsetRefs;
let cell = loadSubslice(slice, bits, refs);
return { code: 'PUSHSLICE', args: [cell, bitsOffset, refsOffset, bits, refs] };
});

@@ -305,11 +303,15 @@ // 9281536 (DUMMY)

let refs = (args >> 7) & 3;
let dataBytes = (args & 127) * 8;
let subslice = fetchSubslice(slice, dataBytes, refs);
return { code: 'PUSHCONT', args: [subslice] };
let bits = (args & 127) * 8;
let bitsOffset = slice.offsetBits;
let refsOffset = slice.offsetRefs;
let cell = loadSubslice(slice, bits, refs);
return { code: 'PUSHCONT', args: [cell, bitsOffset, refsOffset, bits, refs] };
})
CP0Auto.insertHex('9', 4, (slice) => {
let len = slice.loadUint(4) * 8;
let subslice = fetchSubslice(slice, len);
return { code: 'PUSHCONT', args: [subslice] };
let bits = slice.loadUint(4) * 8;
let refs = 0;
let bitsOffset = slice.offsetBits;
let refsOffset = slice.offsetRefs;
let cell = loadSubslice(slice, bits, refs);
return { code: 'PUSHCONT', args: [cell, bitsOffset, refsOffset, bits, refs] };
})

@@ -539,5 +541,7 @@

let refs = slice.loadUint(2);
let dataBits = slice.loadUint(3) * 8 + 1;
let subslice = fetchSubslice(slice, dataBits, refs);
return { code: `STSLICECONST`, args: [subslice] };
let bits = slice.loadUint(3) * 8 + 1;
let bitsOffset = slice.offsetBits;
let refsOffset = slice.offsetRefs;
let cell = loadSubslice(slice, bits, refs);
return { code: `STSLICECONST`, args: [cell, bitsOffset, refsOffset, bits, refs] };
});

@@ -1177,2 +1181,15 @@ CP0Auto.insertHex('d0', 8, { code: 'CTOS' });

export { CP0Auto }
export { CP0Auto }
//
// Utils
//
function loadSubslice(slice: Slice, bits: number, refs?: number) {
let b = beginCell()
.storeBits(slice.loadBits(bits));
for (let i = 0; i < (refs || 0); i++) {
b.storeRef(slice.loadRef());
}
return b.asCell();
}

@@ -77,2 +77,9 @@ import { isOpCodeWithArgs, OpCode } from "./opcodes.gen";

// Slices
if (op.code === 'PUSHSLICE'
|| op.code === 'PUSHCONT'
|| op.code === 'STSLICECONST') {
return `${op.args[0]} ${op.code}`;
}
// Debug

@@ -79,0 +86,0 @@ if (op.code === 'DEBUG') {

@@ -1,2 +0,2 @@

import { beginCell, BitReader, Cell, Dictionary, DictionaryValue } from "ton-core";
import { Cell, Dictionary, DictionaryValue } from "ton-core";
import { opcodeToString } from "../codepage/opcodeToString";

@@ -11,3 +11,4 @@ import { Maybe } from "../utils/maybe";

src: Cell,
srcOffset: number,
offset: { bits: number, refs: number },
limit: { bits: number, refs: number } | null,
root: boolean,

@@ -19,7 +20,7 @@ writer: Writer,

const printer = args.printer;
const hash = args.src.hash().toString('hex');
const writer = args.writer;
const opcodes = decompile({
src: args.src,
srcOffset: args.srcOffset,
offset: args.offset,
limit: args.limit,
allowUnknown: false

@@ -43,3 +44,3 @@ });

let callRefs = new Map<string, string>();
function extract(cell: Cell) {
function extractCallRef(cell: Cell) {

@@ -62,6 +63,7 @@ // Check if we have a call ref

src: cell,
srcOffset: 0,
offset: { bits: 0, refs: 0 },
limit: null,
root: false,
writer: w,
callRefExtractor: extract,
callRefExtractor: extractCallRef,
printer: args.printer

@@ -81,6 +83,7 @@ });

src: value.cell,
srcOffset: value.offset,
offset: { bits: value.offset, refs: 0 },
limit: null,
root: false,
writer: w,
callRefExtractor: extract,
callRefExtractor: extractCallRef,
printer: args.printer

@@ -107,3 +110,3 @@ });

let opstr = `${key} ${value.ref ? 'PROCREF' : 'PROC'}:<{`;
writer.append(printer({ op: opstr, offset: value.srcOffset, length: 0, hash, cell: value.src }, writer.indent));
writer.append(printer({ op: opstr, offset: value.srcOffset, length: 0, hash }, writer.indent));
writer.inIndent(() => {

@@ -115,3 +118,3 @@ value.rendered.split('\n').forEach(line => {

opstr = `}>`;
writer.append(printer({ op: opstr, offset: value.srcOffset, length: 0, hash, cell: value.src }, writer.indent));
writer.append(printer({ op: opstr, offset: value.srcOffset, length: 0, hash }, writer.indent));
}

@@ -125,25 +128,49 @@ });

for (const op of opcodes) {
const opcode = op.op;
// Special cases for call refs
if (op.op.code === 'CALLREF' && args.callRefExtractor) {
let id = args.callRefExtractor(op.op.args[0]);
if (opcode.code === 'CALLREF' && args.callRefExtractor) {
let id = args.callRefExtractor(opcode.args[0]);
let opstr = `${id} INLINECALLDICT`;
writer.append(printer({ op: opstr, offset: op.offset, length: op.length, hash, cell: args.src }, writer.indent));
writer.append(printer({ op: opstr, offset: op.offset, length: op.length, hash: op.hash }, writer.indent));
continue;
}
// Special case for PUSHCONT
if (opcode.code === 'PUSHCONT') {
let opstr = '<{';
writer.append(printer({ op: opstr, offset: op.offset, length: op.length, hash: op.hash }, writer.indent));
writer.inIndent(() => {
decompileCell({
src: args.src,
offset: { bits: opcode.args[1], refs: opcode.args[2] },
limit: { bits: opcode.args[3], refs: opcode.args[4] },
root: false,
writer: writer,
callRefExtractor: args.callRefExtractor,
printer: args.printer
});
})
opstr = '}> ' + op.op.code;
writer.append(printer({ op: opstr, offset: op.offset, length: op.length, hash: op.hash }, writer.indent));
continue;
}
// Special cases for continuations
if (op.op.code === 'PUSHCONT'
|| op.op.code === 'IFREFELSE'
|| op.op.code === 'CALLREF'
|| op.op.code === 'IFJMPREF'
|| op.op.code === 'IFREF'
|| op.op.code === 'IFREFELSEREF') {
let c = op.op.args[0];
if (opcode.code === 'IFREFELSE'
|| opcode.code === 'CALLREF'
|| opcode.code === 'IFJMPREF'
|| opcode.code === 'IFREF'
|| opcode.code === 'IFNOTREF'
|| opcode.code === 'IFNOTJMPREF'
|| opcode.code === 'IFREFELSEREF'
|| opcode.code === 'IFELSEREF') {
let c = opcode.args[0];
let opstr = '<{';
writer.append(printer({ op: opstr, offset: op.offset, length: op.length, hash, cell: args.src }, writer.indent));
writer.append(printer({ op: opstr, offset: op.offset, length: op.length, hash: op.hash }, writer.indent));
writer.inIndent(() => {
decompileCell({
src: c,
srcOffset: 0,
offset: { bits: 0, refs: 0 },
limit: null,
root: false,

@@ -155,4 +182,4 @@ writer: writer,

})
opstr = '}> ' + op.op.code;
writer.append(printer({ op: opstr, offset: op.offset, length: op.length, hash, cell: args.src }, writer.indent));
opstr = '}> ' + opcode.code;
writer.append(printer({ op: opstr, offset: op.offset, length: op.length, hash: op.hash }, writer.indent));
continue;

@@ -162,4 +189,4 @@ }

// Special cases for unknown opcode
if (op.op.code === 'unknown') {
writer.append('!' + op.op.data.toString());
if (opcode.code === 'unknown') {
writer.append('!' + opcode.data.toString());
continue;

@@ -169,4 +196,4 @@ }

// All remaining opcodes
let opstr = opcodeToString(op.op);
writer.append(printer({ op: opstr, offset: op.offset, length: op.length, hash, cell: args.src }, writer.indent));
let opstr = opcodeToString(opcode);
writer.append(printer({ op: opstr, offset: op.offset, length: op.length, hash: op.hash }, writer.indent));
}

@@ -186,3 +213,4 @@ }

src,
srcOffset: 0,
offset: { bits: 0, refs: 0 },
limit: null,
root: true,

@@ -201,14 +229,7 @@ writer,

parse: (src) => {
let bitsReader = ((src as any)._reader.clone() as BitReader);
let offset = (bitsReader as any)._offset as number;
bitsReader.reset();
let bits = bitsReader.loadBits(bitsReader.remaining);
let b = beginCell()
.storeBits(bits);
while (src.remainingRefs > 0) {
b.storeRef(src.loadRef());
}
return { offset, cell: b.endCell() };
let cloned = src.clone(true);
let offset = src.offsetBits;
return { offset, cell: cloned.asCell() };
}
};
}

@@ -5,2 +5,3 @@ import { beginCell, Cell, Slice } from "ton-core";

import { Maybe } from "../utils/maybe";
import { subcell } from "../utils/subcell";

@@ -10,2 +11,3 @@ export type DecompiledOpCode = OpCode | { code: 'unknown', data: Cell };

op: DecompiledOpCode,
hash: string,
offset: number,

@@ -15,3 +17,8 @@ length: number

export function decompile(args: { src: Cell | Slice | Buffer, srcOffset?: Maybe<number>, allowUnknown?: boolean }): DecompiledInstruction[] {
export function decompile(args: {
src: Cell | Buffer,
offset?: Maybe<{ bits: number, refs: number }>,
limit?: Maybe<{ bits: number, refs: number }>,
allowUnknown?: boolean
}): DecompiledInstruction[] {

@@ -22,31 +29,43 @@ // Result collection

// Load slice
let sc: Slice;
let source: Cell;
if (Buffer.isBuffer(args.src)) {
sc = Cell.fromBoc(args.src)[0].beginParse();
source = Cell.fromBoc(args.src)[0];
} else if (args.src instanceof Cell) {
sc = args.src.beginParse();
source = args.src;
} else {
sc = args.src;
throw new Error('Invalid source');
}
// Hash
let hash = source.hash().toString('hex');
// Prepare offset
let sco = args.srcOffset || 0;
if (args.srcOffset && args.srcOffset > 0) {
sc.skip(args.srcOffset);
let bitsDelta = 0;
let refsDelta = 0;
if (args.offset) {
bitsDelta = args.offset.bits;
refsDelta = args.offset.refs;
}
// Prepare remaining tracker
let scl = sc.remainingBits;
// Prepare offset
let bitsLimit = args.limit ? (args.limit.bits + bitsDelta) : source.bits.length;
let refsLimit = args.limit ? (args.limit.refs + refsDelta) : source.refs.length;
let slice = subcell({
cell: source,
bits: bitsLimit,
refs: refsLimit
}).beginParse();
if (args.offset) {
slice.skip(args.offset.bits);
for (let i = 0; i < args.offset.refs; i++)
slice.loadRef();
}
while (sc.remainingBits > 0) {
while (slice.remainingBits > 0) {
// Load opcode
const opcode = loadOpcode(sc);
const opcodeOffset = slice.offsetBits;
const opcode = loadOpcode(slice);
const opcodeLength = slice.offsetBits - opcodeOffset;
// Update state
let currentOffset = sco; // Persisted offset before reading opcode
let currentLength = scl - sc.remainingBits; // Check difference in remaining bits to calculate opcode length
scl -= currentLength;
sco += currentLength;
// Failed case

@@ -59,3 +78,3 @@ if (!opcode.ok) {

}
fullCell.storeSlice(sc);
fullCell.storeSlice(slice);
result.push({

@@ -66,4 +85,5 @@ op: {

},
offset: currentOffset,
length: currentLength
hash,
offset: opcodeOffset,
length: opcodeLength
});

@@ -79,11 +99,12 @@ break;

op: opcode.read,
offset: currentOffset,
length: currentLength
hash,
offset: opcodeOffset,
length: opcodeLength
});
// Implicit jump
if (sc.remainingBits === 0 && sc.remainingRefs > 0) {
sc = sc.loadRef().beginParse();
scl = sc.remainingBits;
sco = 0;
if (slice.remainingBits === 0 && slice.remainingRefs > 0) {
let n = slice.loadRef();
hash = n.hash().toString('hex');
slice = n.beginParse();
}

@@ -90,0 +111,0 @@ }

@@ -1,5 +0,3 @@

import { Cell } from "ton-core";
export type Printer = (src: string | { op: string, hash: string, offset: number, length: number }, indent: number) => string;
export type Printer = (src: string | { op: string, hash: string, cell: Cell, offset: number, length: number }, indent: number) => string;
export function createTextPrinter(indentWidth: number): Printer {

@@ -6,0 +4,0 @@ return (src, indent) => {

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc