Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix object parser #45

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
20 changes: 11 additions & 9 deletions src/client/TonClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
OpenedContract
} from '@ton/core';
import { Maybe } from "../utils/maybe";
import { StackItem, Value } from "../utils/stack";

export type TonClientParameters = {
/**
Expand Down Expand Up @@ -338,16 +339,17 @@ export class TonClient {
}
}

function parseStackEntry(x: any): any {
function parseStackEntry(x: Value): TupleItem {
const typeName = x['@type'];
switch(typeName) {
case 'tvm.list':
return { type: 'tuple', items: x.elements.map(parseStackEntry) }
case 'tvm.tuple':
return x.elements.map(parseStackEntry);
return { type: 'tuple', items: x.elements.map(parseStackEntry) };
case 'tvm.cell':
return Cell.fromBoc(Buffer.from(x.bytes, 'base64'))[0];
return { type: 'cell', cell: Cell.fromBoc(Buffer.from(x.bytes, 'base64'))[0] }
case 'tvm.slice':
return Cell.fromBoc(Buffer.from(x.bytes, 'base64'))[0];
return { type: 'slice', cell: Cell.fromBoc(Buffer.from(x.bytes, 'base64'))[0] }
case 'tvm.stackEntryCell':
return parseStackEntry(x.cell);
case 'tvm.stackEntrySlice':
Expand All @@ -359,13 +361,13 @@ function parseStackEntry(x: any): any {
case 'tvm.stackEntryNumber':
return parseStackEntry(x.number);
case 'tvm.numberDecimal':
return BigInt(x.number);
return { type: 'int', value: BigInt(x.number) }
default:
throw Error('Unsupported item type: ' + typeName);
}
}

function parseStackItem(s: any): TupleItem {
function parseStackItem(s: StackItem): TupleItem {
if (s[0] === 'num') {
let val = s[1] as string;
if (val.startsWith('-')) {
Expand All @@ -392,11 +394,11 @@ function parseStackItem(s: any): TupleItem {
}
}

function parseStack(src: any[]) {
function parseStack(src: unknown[]) {
let stack: TupleItem[] = [];

for (let s of src) {
stack.push(parseStackItem(s));
stack.push(parseStackItem(s as StackItem));
}

return new TupleReader(stack);
Expand Down Expand Up @@ -523,4 +525,4 @@ function createProvider(client: TonClient, address: Address, init: StateInit | n
return client.getTransactions(address, { limit: limit ?? 100, lt: lt.toString(), hash: hash.toString('base64'), inclusive: true });
}
}
}
}
66 changes: 66 additions & 0 deletions src/utils/stack.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { z } from 'zod';

// Plain types for TON Virtual Machine values
type NumberDecimal = { '@type': 'tvm.numberDecimal', number: string };
type StackEntryNumber = { '@type': 'tvm.stackEntryNumber', number: NumberDecimal };

type Slice = { '@type': 'tvm.slice', bytes: string };
type StackEntrySlice = { '@type': 'tvm.stackEntrySlice', slice: Slice };

type Cell = { '@type': 'tvm.cell', bytes: string };
type StackEntryCell = { '@type': 'tvm.stackEntryCell', cell: Cell };

// Structured types for TON Virtual Machine values
export type List = { '@type': 'tvm.list', elements: Value[] };
type StackEntryList = { '@type': 'tvm.stackEntryList', list: List };

export type Tuple = { '@type': 'tvm.tuple', elements: Value[] };
type StackEntryTuple = { '@type': 'tvm.stackEntryTuple', tuple: Tuple };

// Union of all TON Virtual Machine values
type CommonValue = NumberDecimal | Cell | Slice | List | Tuple;
type StackEntryValue = StackEntryCell | StackEntryNumber | StackEntrySlice | StackEntryList | StackEntryTuple;
export type Value = CommonValue | StackEntryValue;


// zod definitions

const serializedCellSchema = z.object({
bytes: z.string(),
});
type SerializedCell = z.infer<typeof serializedCellSchema>;

const nullSchema = z.union([
z.tuple([z.literal('null')]),
z.tuple([z.literal('null'), z.null().optional()]),
]);
type NullStackItem = z.infer<typeof nullSchema>;

const numSchema = z.tuple([z.literal('num'), z.string()]);
type NumStackItem = z.infer<typeof numSchema>;

const cellSchema = z.tuple([z.literal('cell'), serializedCellSchema]);
type CellStackItem = z.infer<typeof cellSchema>;

const sliceSchema = z.tuple([z.literal('slice'), serializedCellSchema]);
type SliceStackItem = z.infer<typeof sliceSchema>;

const builderSchema = z.tuple([z.literal('builder'), serializedCellSchema]);
type BuilderStackItem = z.infer<typeof builderSchema>;

const tupleSchema = z.tuple([z.literal('tuple'), z.unknown() as z.ZodType<Tuple>]);
type TupleStackItem = z.infer<typeof tupleSchema>;

const listSchema = z.tuple([z.literal('list'), z.unknown() as z.ZodType<List>]);
type ListStackItem = z.infer<typeof listSchema>;

export const stackItemSchema = z.union([
nullSchema,
numSchema,
cellSchema,
sliceSchema,
builderSchema,
tupleSchema,
listSchema,
]);
export type StackItem = NullStackItem | NumStackItem | CellStackItem | SliceStackItem | BuilderStackItem | TupleStackItem | ListStackItem;