ton3-core
Version:
TON low-level API tools
199 lines • 6.62 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Builder = void 0;
const address_1 = require("../address");
const slice_1 = require("./slice");
const cell_1 = require("./cell");
const helpers_1 = require("../utils/helpers");
class Builder {
constructor(size = 1023) {
this._size = size;
this._bits = [];
this._refs = [];
}
checkSliceType(slice) {
if (slice instanceof slice_1.Slice === false) {
throw new Error('Builder: can\'t store slice, because it\'s type is not a Slice.');
}
}
checkAddressType(address) {
if (address instanceof address_1.Address === false) {
throw new Error('Builder: can\'t store address, because it\'s type is not an Address.');
}
}
checkBitsTypeAndNormalize(bits) {
return bits.map(bit => {
if (bit !== 0 && bit !== 1 && bit !== false && bit !== true) {
throw new Error('Builder: can\'t store bit, because it\'s type is not a Number or Boolean, or value doesn\'t equals 0 nor 1.');
}
return (bit === 1 || bit === true) ? 1 : 0;
});
}
checkBitsOverflow(size) {
if (size > this.remainder) {
throw new Error(`Builder: bits overflow. Can't add ${size} bits. Only ${this.remainder} bits left.`);
}
}
checkRefsType(refs) {
if (!refs.every(cell => cell instanceof cell_1.Cell === true)) {
throw new Error('Builder: can\'t store ref, because it\'s type is not a Cell.');
}
}
checkRefsOverflow(size) {
if (size > (4 - this._refs.length)) {
throw new Error(`Builder: refs overflow. Can't add ${size} refs. Only ${4 - this._refs.length} refs left.`);
}
}
storeNumber(value, size) {
const bits = Array.from({ length: size })
.map((_el, i) => Number(((value >> BigInt(i)) & 1n) === 1n))
.reverse();
this.storeBits(bits);
return this;
}
get size() {
return this._size;
}
get bits() {
return Array.from(this._bits);
}
get bytes() {
return (0, helpers_1.bitsToBytes)(this._bits);
}
get refs() {
return Array.from(this._refs);
}
get remainder() {
return this._size - this._bits.length;
}
storeSlice(slice) {
this.checkSliceType(slice);
const { bits, refs } = slice;
this.checkBitsOverflow(bits.length);
this.checkRefsOverflow(refs.length);
this.storeBits(bits);
refs.forEach(ref => this.storeRef(ref));
return this;
}
storeRef(ref) {
this.checkRefsType([ref]);
this.checkRefsOverflow(1);
this._refs.push(ref);
return this;
}
storeMaybeRef(ref) {
if (ref === null) {
return this.storeBit(0);
}
return this.storeBit(1).storeRef(ref);
}
storeRefs(refs) {
this.checkRefsType(refs);
this.checkRefsOverflow(refs.length);
this._refs.push(...refs);
return this;
}
storeBit(bit) {
const value = this.checkBitsTypeAndNormalize([bit]);
this.checkBitsOverflow(1);
this._bits = this._bits.concat(value);
return this;
}
storeBits(bits) {
const value = this.checkBitsTypeAndNormalize(bits);
this.checkBitsOverflow(value.length);
this._bits = this._bits.concat(value);
return this;
}
storeInt(value, size) {
const int = BigInt(value);
const intBits = 1n << (BigInt(size) - 1n);
if (int < -intBits || int >= intBits) {
throw new Error('Builder: can\'t store an Int, because its value allocates more space than provided.');
}
this.storeNumber(int, size);
return this;
}
storeUint(value, size) {
const uint = BigInt(value);
if (uint < 0 || uint >= (1n << BigInt(size))) {
throw new Error('Builder: can\'t store an UInt, because its value allocates more space than provided.');
}
this.storeNumber(uint, size);
return this;
}
storeVarInt(value, length) {
const int = BigInt(value);
const size = Math.ceil(Math.log2(length));
const sizeBytes = Math.ceil((int.toString(2).length) / 8);
const sizeBits = sizeBytes * 8;
this.checkBitsOverflow(size + sizeBits);
return int === 0n
? this.storeUint(0, size)
: this.storeUint(sizeBytes, size).storeInt(value, sizeBits);
}
storeVarUint(value, length) {
const uint = BigInt(value);
const size = Math.ceil(Math.log2(length));
const sizeBytes = Math.ceil((uint.toString(2).length) / 8);
const sizeBits = sizeBytes * 8;
this.checkBitsOverflow(size + sizeBits);
return uint === 0n
? this.storeUint(0, size)
: this.storeUint(sizeBytes, size).storeUint(value, sizeBits);
}
storeBytes(value) {
this.checkBitsOverflow(value.length * 8);
Uint8Array.from(value).forEach((byte) => this.storeUint(byte, 8));
return this;
}
storeString(value) {
const bytes = (0, helpers_1.stringToBytes)(value);
this.storeBytes(bytes);
return this;
}
storeAddress(address) {
if (address === null) {
this.storeBits([0, 0]);
return this;
}
const anycast = 0;
const addressBitsSize = 2 + 1 + 8 + 256;
this.checkAddressType(address);
this.checkBitsOverflow(addressBitsSize);
this.storeBits([1, 0]);
this.storeUint(anycast, 1);
this.storeInt(address.workchain, 8);
this.storeBytes(address.hash);
return this;
}
storeCoins(coins) {
if (coins.isNegative()) {
throw new Error('Builder: coins value can\'t be negative.');
}
const nano = BigInt(coins.toNano());
this.storeVarUint(nano, 16);
return this;
}
storeDict(hashmap) {
const slice = hashmap.cell().slice();
this.storeSlice(slice);
return this;
}
clone() {
const data = new Builder(this._size);
data.storeBits(this.bits);
this.refs.forEach(ref => data.storeRef(ref));
return data;
}
cell(type = cell_1.CellType.Ordinary) {
const cell = new cell_1.Cell({
bits: this.bits,
refs: this.refs,
type
});
return cell;
}
}
exports.Builder = Builder;
//# sourceMappingURL=builder.js.map