ton3-liteclient
Version:
TON Blockchain LiteClient
368 lines • 14.2 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BlockchainClient = void 0;
const core_1 = require("@tonkite/core");
const ton3_core_1 = require("ton3-core");
const stack_1 = require("../../utils/stack");
const types_1 = require("@tonkite/types");
const cursor_1 = require("./cursor");
class BlockchainClient {
constructor(api) {
this.api = api;
}
async getMasterchainInfo() {
const masterchainInfo = await this.api.getMasterchainInfo();
return {
workchain: masterchainInfo.last.workchain,
shard: masterchainInfo.last.shard,
seqno: masterchainInfo.last.seqno,
rootHash: masterchainInfo.last.root_hash,
fileHash: masterchainInfo.last.file_hash,
};
}
async getAllShardsInfo(blockId) {
const allShards = await this.api.getAllShardsInfo({
workchain: blockId.workchain,
shard: blockId.shard,
seqno: blockId.seqno,
root_hash: blockId.rootHash,
file_hash: blockId.fileHash,
});
const [cell] = ton3_core_1.BOC.from(allShards.data);
const shardHashes = (0, types_1.loadShardHashes)(cell.slice());
return shardHashes
.map((workchain) => workchain.shards.map((shard) => ({
workchain: workchain.workchain,
shard: shard.id,
seqno: shard.description.seq_no,
rootHash: shard.description.root_hash,
fileHash: shard.description.file_hash,
})))
.flat();
}
async lookupBlock(blockId) {
const result = await this.api.lookupBlock({
id: {
workchain: blockId.workchain,
shard: blockId.shard,
seqno: blockId.seqno,
},
});
return {
workchain: result.id.workchain,
shard: result.id.shard,
seqno: result.id.seqno,
rootHash: result.id.root_hash,
fileHash: result.id.file_hash,
};
}
async getAccountState(account, blockId) {
const accountStateRaw = await this.api.getAccountState({
workchain: blockId.workchain,
shard: blockId.shard,
seqno: blockId.seqno,
root_hash: blockId.rootHash,
file_hash: blockId.fileHash,
}, {
workchain: account.workchain,
id: account.hash,
});
if (!accountStateRaw.state.length) {
return new core_1.Account({
workchain: accountStateRaw.id.workchain,
shard: accountStateRaw.id.shard,
seqno: accountStateRaw.id.seqno,
rootHash: accountStateRaw.id.root_hash,
fileHash: accountStateRaw.id.file_hash,
}, account, ton3_core_1.Coins.fromNano(0), {
lt: 0n,
hash: new Uint8Array(32),
}, core_1.AccountStatus.UNINITIALIZED, null, null, null, {
lastPaid: null,
duePayment: null,
usage: {
bits: 0,
cells: 0,
publicCells: 0,
},
});
}
const proof = ton3_core_1.BOC.from(accountStateRaw.proof);
const loadShardIdent = (slice) => {
if (slice.loadUint(2) !== 0b00) {
throw new Error('Incorrect ShardIdent');
}
const shardPrefixBits = slice.loadBigUint(6);
const workchainId = slice.loadInt(32);
const shardPrefix = slice.loadBigUint(64);
return {
shardPrefixBits,
workchainId,
shardPrefix,
};
};
const loadDepthBalanceInfo = (slice) => {
const splitDepth = slice.loadUint(5);
const balance = (0, types_1.loadCurrencyCollection)(slice);
return {
splitDepth,
balance,
};
};
const loadShardAccounts = (slice) => {
return [
...ton3_core_1.Hashmap.parse(256, ton3_core_1.Slice.parse(slice.refs[0]), {
deserializers: {
key: ton3_core_1.Utils.Helpers.bitsToBytes,
value: (cell) => {
const cs = ton3_core_1.Slice.parse(cell);
const depthBalanceInfo = loadDepthBalanceInfo(cs);
const shardAccount = (0, types_1.loadShardAccount)(cs);
return {
shardAccount,
depthBalanceInfo,
};
},
},
}),
];
};
const loadShardStateUnsplit = (slice) => {
if (slice.loadUint(32) !== 0x9023afe2) {
throw new Error('Incorrect ShardStateUnsplit');
}
const global_id = slice.loadInt(32);
const shard_id = loadShardIdent(slice);
const seq_no = slice.loadUint(32);
const vert_seq_no = slice.loadUint(32);
const gen_utime = slice.loadUint(32);
const gen_lt = slice.loadBigUint(64);
const min_ref_mc_seqno = slice.loadUint(32);
const out_msg_queue_info = slice.loadRef();
const before_split = slice.loadBit();
const shardAccounts = loadShardAccounts(ton3_core_1.Slice.parse(slice.loadRef()));
const next = ton3_core_1.Slice.parse(slice.loadRef());
const overload_history = next.loadBigUint(64);
const underload_history = next.loadBigUint(64);
return {
global_id,
shard_id,
seq_no,
vert_seq_no,
gen_utime,
gen_lt,
min_ref_mc_seqno,
out_msg_queue_info,
before_split,
shardAccounts,
overload_history,
underload_history,
};
};
const [cell] = ton3_core_1.BOC.from(accountStateRaw.state);
const shardState = loadShardStateUnsplit(ton3_core_1.Slice.parse(proof[1].refs[0]));
const accountState = (0, types_1.loadAccount)(cell.slice());
const shardAccount = shardState.shardAccounts
.filter(([accountHash]) => {
return Buffer.from(accountHash).equals(Buffer.from(account.hash, 0));
})
.map(([_, { shardAccount }]) => shardAccount)[0];
return new core_1.Account({
workchain: accountStateRaw.id.workchain,
shard: accountStateRaw.id.shard,
seqno: accountStateRaw.id.seqno,
rootHash: accountStateRaw.id.root_hash,
fileHash: accountStateRaw.id.file_hash,
}, account, accountState.storage.balance.coins, {
lt: shardAccount.lastTransactionId.lt,
hash: shardAccount.lastTransactionId.hash,
}, accountState.storage.state.type, accountState.storage.state.type === 'frozen' ? accountState.storage.state.stateHash : null, accountState.storage.state.type === 'active' ? accountState.storage.state.code : null, accountState.storage.state.type === 'active' ? accountState.storage.state.data : null, {
lastPaid: new Date(accountState.storageStat.lastPaid * 1000),
duePayment: accountState.storageStat.duePayment,
usage: {
bits: accountState.storageStat.used.bits,
cells: accountState.storageStat.used.cells,
publicCells: accountState.storageStat.used.publicCells,
},
});
}
shardIdent(slice) {
slice.skipBits(2);
const shard_pfx_bits = slice.loadBits(Math.ceil(Math.log2(60)));
const workchain_id = slice.loadInt(32);
const shard_prefix = slice.loadBigUint(64);
return {
shard_pfx_bits,
workchain_id,
shard_prefix
};
}
globalVersion(slice) {
slice.skipBits(8);
const version = slice.loadUint(32);
const capabilities = slice.loadBigUint(64);
return {
version,
capabilities
};
}
extBlkRef(slice) {
const end_lt = slice.loadBigUint(64);
const seq_no = slice.loadUint(32);
const root_hash = slice.loadBytes(256);
const file_hash = slice.loadBytes(256);
return {
end_lt,
seq_no,
root_hash,
file_hash
};
}
blkMasterInfo(slice) {
const master = this.extBlkRef(slice);
return {
master
};
}
blkPrevInfo(slice, arg) {
if (arg === 0) {
return this.extBlkRef(slice);
}
return [
this.extBlkRef(slice.loadRef().slice()),
this.extBlkRef(slice.loadRef().slice())
];
}
blkInfo(slice) {
slice.skipBits(32);
const version = slice.loadUint(32);
const not_master = slice.loadBit();
const after_merge = slice.loadBit();
const before_split = slice.loadBit();
const after_split = slice.loadBit();
const want_split = Boolean(slice.loadBit());
const want_merge = Boolean(slice.loadBit());
const key_block = Boolean(slice.loadBit());
const vert_seqno_incr = slice.loadBit();
const flags = slice.loadUint(8);
const seq_no = slice.loadUint(32);
const vert_seq_no = slice.loadUint(32);
const shard = this.shardIdent(slice);
const gen_utime = slice.loadUint(32);
const start_lt = slice.loadBigUint(64);
const end_lt = slice.loadBigUint(64);
const gen_validator_list_hash_short = slice.loadUint(32);
const gen_catchain_seqno = slice.loadUint(32);
const min_ref_mc_seqno = slice.loadUint(32);
const prev_key_block_seqno = slice.loadUint(32);
const gen_software = (flags & (1 << 0)) ? this.globalVersion(slice) : null;
const master_ref = Boolean(not_master) ? this.blkMasterInfo(slice.loadRef().slice()) : null;
const prev_ref = this.blkPrevInfo(slice.loadRef().slice(), after_merge);
const prev_vert_ref = Boolean(vert_seqno_incr) ? this.blkPrevInfo(slice.loadRef().slice(), 0) : null;
return {
version,
not_master,
after_merge,
before_split,
after_split,
want_split,
want_merge,
key_block,
vert_seqno_incr,
flags,
seq_no,
vert_seq_no,
shard,
gen_utime,
start_lt,
end_lt,
gen_validator_list_hash_short,
gen_catchain_seqno,
min_ref_mc_seqno,
prev_key_block_seqno,
gen_software,
master_ref,
prev_ref,
prev_vert_ref
};
}
async getBlock(blockId) {
const { data } = await this.api.getBlock({
workchain: blockId.workchain,
shard: blockId.shard,
seqno: blockId.seqno,
root_hash: blockId.rootHash,
file_hash: blockId.fileHash
});
const slice = ton3_core_1.BOC.from(data).root[0].slice();
slice.skipBits(32);
const global_id = slice.loadInt(32);
const info = this.blkInfo(slice.loadRef().slice());
const value_flow = slice.loadRef();
const state_update = slice.loadRef();
const extra = slice.loadRef();
return {
global_id,
info,
value_flow,
state_update,
extra
};
}
async getBlockTransactions(blockId, after = null) {
const result = await this.api.listBlockTransactions({
workchain: blockId.workchain,
shard: blockId.shard,
seqno: blockId.seqno,
root_hash: blockId.rootHash,
file_hash: blockId.fileHash,
}, 40, after
? {
account: after.account.hash,
lt: after.lt,
}
: null);
return result.ids.map((id) => ({
account: new ton3_core_1.Address(`${result.id.workchain}:${ton3_core_1.Utils.Helpers.bytesToHex(id.account)}`),
lt: id.lt,
hash: id.hash,
}));
}
async getOneTransaction(blockId, account, lt) {
return await this.api.getOneTransaction({
workchain: blockId.workchain,
shard: blockId.shard,
seqno: blockId.seqno,
root_hash: blockId.rootHash,
file_hash: blockId.fileHash
}, account, lt);
}
getTransactions(account, after, take = Infinity) {
return new cursor_1.TransactionCursor(this.api, account, after, take);
}
async invokeGetMethod(account, method, stack = []) {
const methodName = typeof method !== 'number' ? ton3_core_1.Utils.Helpers.stringToBytes(method) : null;
const methodId = BigInt(typeof method !== 'number' ? (ton3_core_1.Utils.Checksum.crc16(methodName) & 0xffff) | 0x10000 : method);
const _stack = stack_1.Stack.serialize(stack);
const data = await this.api.runSmcMethod({
workchain: account.blockId.workchain,
shard: account.blockId.shard,
seqno: account.blockId.seqno,
root_hash: account.blockId.rootHash,
file_hash: account.blockId.fileHash
}, {
workchain: account.address.workchain,
id: account.address.hash
}, methodId, new ton3_core_1.BOC([_stack]).toBytes());
const result = {
...data,
result: data.result ? stack_1.Stack.deserialize(ton3_core_1.BOC.from(data.result).root[0]) : null
};
return result;
}
async getTime() {
return await this.api.getTime();
}
}
exports.BlockchainClient = BlockchainClient;
//# sourceMappingURL=index.js.map