@ton/core
Version:
Core TypeScript library that implements low level primitives for TON blockchain.
497 lines (452 loc) • 12.2 kB
text/typescript
/**
* Copyright (c) Whales Corp.
* All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import { Address } from "../address/Address";
import { ExternalAddress } from "../address/ExternalAddress";
import { BitBuilder } from "./BitBuilder";
import { BitString } from "./BitString";
import { Writable } from "./Writable";
import { Cell } from "./Cell";
import { Slice } from "./Slice";
import { writeString } from "./utils/strings";
import { Dictionary, DictionaryKey, DictionaryKeyTypes, DictionaryValue } from "../dict/Dictionary";
import { Maybe } from "../utils/maybe";
/**
* Start building a cell
* @returns a new builder
*/
export function beginCell() {
return new Builder();
}
/**
* Builder for Cells
*/
export class Builder {
private _bits: BitBuilder;
private _refs: Cell[];
constructor() {
this._bits = new BitBuilder();
this._refs = [];
}
/**
* Bits written so far
*/
get bits() {
return this._bits.length;
}
/**
* References written so far
*/
get refs() {
return this._refs.length;
}
/**
* Available bits
*/
get availableBits() {
return 1023 - this.bits;
}
/**
* Available references
*/
get availableRefs() {
return 4 - this.refs;
}
/**
* Write a single bit
* @param value bit to write, true or positive number for 1, false or zero or negative for 0
* @returns this builder
*/
storeBit(value: boolean | number) {
this._bits.writeBit(value);
return this;
}
/**
* Write bits from BitString
* @param src source bits
* @returns this builder
*/
storeBits(src: BitString) {
this._bits.writeBits(src);
return this;
}
/**
* Store Buffer
* @param src source buffer
* @param bytes optional number of bytes to write
* @returns this builder
*/
storeBuffer(src: Buffer, bytes?: Maybe<number>) {
if (bytes !== undefined && bytes !== null) {
if (src.length !== bytes) {
throw Error(`Buffer length ${src.length} is not equal to ${bytes}`);
}
}
this._bits.writeBuffer(src);
return this;
}
/**
* Store Maybe Buffer
* @param src source buffer or null
* @param bytes optional number of bytes to write
* @returns this builder
*/
storeMaybeBuffer(src: Buffer | null, bytes?: Maybe<number>) {
if (src !== null) {
this.storeBit(1);
this.storeBuffer(src, bytes);
} else {
this.storeBit(0);
}
return this;
}
/**
* Store uint value
* @param value value as bigint or number
* @param bits number of bits to write
* @returns this builder
*/
storeUint(value: bigint | number, bits: number) {
this._bits.writeUint(value, bits);
return this;
}
/**
* Store maybe uint value
* @param value value as bigint or number, null or undefined
* @param bits number of bits to write
* @returns this builder
*/
storeMaybeUint(value: Maybe<number | bigint>, bits: number) {
if (value !== null && value !== undefined) {
this.storeBit(1);
this.storeUint(value, bits);
} else {
this.storeBit(0);
}
return this;
}
/**
* Store int value
* @param value value as bigint or number
* @param bits number of bits to write
* @returns this builder
*/
storeInt(value: bigint | number, bits: number) {
this._bits.writeInt(value, bits);
return this;
}
/**
* Store maybe int value
* @param value value as bigint or number, null or undefined
* @param bits number of bits to write
* @returns this builder
*/
storeMaybeInt(value: Maybe<number | bigint>, bits: number) {
if (value !== null && value !== undefined) {
this.storeBit(1);
this.storeInt(value, bits);
} else {
this.storeBit(0);
}
return this;
}
/**
* Store varuint value
* @param value value as bigint or number
* @param bits number of bits to write to header
* @returns this builder
*/
storeVarUint(value: number | bigint, bits: number) {
this._bits.writeVarUint(value, bits);
return this;
}
/**
* Store maybe varuint value
* @param value value as bigint or number, null or undefined
* @param bits number of bits to write to header
* @returns this builder
*/
storeMaybeVarUint(value: Maybe<number | bigint>, bits: number) {
if (value !== null && value !== undefined) {
this.storeBit(1);
this.storeVarUint(value, bits);
} else {
this.storeBit(0);
}
return this;
}
/**
* Store varint value
* @param value value as bigint or number
* @param bits number of bits to write to header
* @returns this builder
*/
storeVarInt(value: number | bigint, bits: number) {
this._bits.writeVarInt(value, bits);
return this;
}
/**
* Store maybe varint value
* @param value value as bigint or number, null or undefined
* @param bits number of bits to write to header
* @returns this builder
*/
storeMaybeVarInt(value: Maybe<number | bigint>, bits: number) {
if (value !== null && value !== undefined) {
this.storeBit(1);
this.storeVarInt(value, bits);
} else {
this.storeBit(0);
}
return this;
}
/**
* Store coins value
* @param amount amount of coins
* @returns this builder
*/
storeCoins(amount: number | bigint) {
this._bits.writeCoins(amount);
return this;
}
/**
* Store maybe coins value
* @param amount amount of coins, null or undefined
* @returns this builder
*/
storeMaybeCoins(amount: Maybe<number | bigint>) {
if (amount !== null && amount !== undefined) {
this.storeBit(1);
this.storeCoins(amount);
} else {
this.storeBit(0);
}
return this;
}
/**
* Store address
* @param addres address to store
* @returns this builder
*/
storeAddress(address: Maybe<Address | ExternalAddress>) {
this._bits.writeAddress(address);
return this;
}
/**
* Store reference
* @param cell cell or builder to store
* @returns this builder
*/
storeRef(cell: Cell | Builder) {
// Check refs
if (this._refs.length >= 4) {
throw new Error("Too many references");
}
// Store reference
if (cell instanceof Cell) {
this._refs.push(cell);
} else if (cell instanceof Builder) {
this._refs.push(cell.endCell());
} else {
throw new Error("Invalid argument");
}
return this;
}
/**
* Store reference if not null
* @param cell cell or builder to store
* @returns this builder
*/
storeMaybeRef(cell?: Maybe<Cell | Builder>) {
if (cell) {
this.storeBit(1);
this.storeRef(cell);
} else {
this.storeBit(0);
}
return this;
}
/**
* Store slice it in this builder
* @param src source slice
*/
storeSlice(src: Slice) {
let c = src.clone();
if (c.remainingBits > 0) {
this.storeBits(c.loadBits(c.remainingBits));
}
while (c.remainingRefs > 0) {
this.storeRef(c.loadRef());
}
return this;
}
/**
* Store slice in this builder if not null
* @param src source slice
*/
storeMaybeSlice(src?: Maybe<Slice>) {
if (src) {
this.storeBit(1);
this.storeSlice(src);
} else {
this.storeBit(0);
}
return this;
}
/**
* Store builder
* @param src builder to store
* @returns this builder
*/
storeBuilder(src: Builder) {
return this.storeSlice(src.endCell().beginParse());
}
/**
* Store builder if not null
* @param src builder to store
* @returns this builder
*/
storeMaybeBuilder(src?: Maybe<Builder>) {
if (src) {
this.storeBit(1);
this.storeBuilder(src);
} else {
this.storeBit(0);
}
return this;
}
/**
* Store writer or builder
* @param writer writer or builder to store
* @returns this builder
*/
storeWritable(writer: ((builder: Builder) => void) | Writable) {
if (typeof writer === 'object') {
writer.writeTo(this);
} else {
writer(this);
}
return this;
}
/**
* Store writer or builder if not null
* @param writer writer or builder to store
* @returns this builder
*/
storeMaybeWritable(writer?: Maybe<((builder: Builder) => void) | Writable>) {
if (writer) {
this.storeBit(1);
this.storeWritable(writer);
} else {
this.storeBit(0);
}
return this;
}
/**
* Store object in this builder
* @param writer Writable or writer functuin
*/
store(writer: ((builder: Builder) => void) | Writable) {
this.storeWritable(writer);
return this;
}
/**
* Store string tail
* @param src source string
* @returns this builder
*/
storeStringTail(src: string) {
writeString(src, this);
return this;
}
/**
* Store string tail
* @param src source string
* @returns this builder
*/
storeMaybeStringTail(src?: Maybe<string>) {
if (src !== null && src !== undefined) {
this.storeBit(1);
writeString(src, this);
} else {
this.storeBit(0);
}
return this;
}
/**
* Store string tail in ref
* @param src source string
* @returns this builder
*/
storeStringRefTail(src: string) {
this.storeRef(beginCell()
.storeStringTail(src));
return this;
}
/**
* Store maybe string tail in ref
* @param src source string
* @returns this builder
*/
storeMaybeStringRefTail(src?: Maybe<string | null>) {
if (src !== null && src !== undefined) {
this.storeBit(1);
this.storeStringRefTail(src);
} else {
this.storeBit(0);
}
return this;
}
/**
* Store dictionary in this builder
* @param dict dictionary to store
* @returns this builder
*/
storeDict<K extends DictionaryKeyTypes, V>(dict?: Maybe<Dictionary<K, V>>, key?: Maybe<DictionaryKey<K>>, value?: Maybe<DictionaryValue<V>>) {
if (dict) {
dict.store(this, key, value);
} else {
this.storeBit(0);
}
return this;
}
/**
* Store dictionary in this builder directly
* @param dict dictionary to store
* @returns this builder
*/
storeDictDirect<K extends DictionaryKeyTypes, V>(dict: Dictionary<K, V>, key?: Maybe<DictionaryKey<K>>, value?: Maybe<DictionaryValue<V>>) {
dict.storeDirect(this, key, value);
return this;
}
/**
* Complete cell
* @param opts options
* @returns cell
*/
endCell(opts?: { exotic?: boolean }) {
return new Cell({
bits: this._bits.build(),
refs: this._refs,
exotic: opts?.exotic
});
}
/**
* Convert to cell
* @returns cell
*/
asCell() {
return this.endCell();
}
/**
* Convert to slice
* @returns slice
*/
asSlice() {
return this.endCell().beginParse();
}
}