@ton.js/core
Version:
TonWeb - JavaScript API for TON blockchain
183 lines • 6.56 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Address = void 0;
const base64_1 = require("./base64");
const workchain_1 = require("./workchain");
const common_1 = require("./common");
var Flags;
(function (Flags) {
Flags[Flags["Bounceable"] = 17] = "Bounceable";
Flags[Flags["NonBounceable"] = 81] = "NonBounceable";
Flags[Flags["Test"] = 128] = "Test";
})(Flags || (Flags = {}));
class Address {
constructor(address) {
if (!address) {
throw new Error(`Empty address specified: it must be ` +
`either Address instance or string`);
}
if (address instanceof Address) {
this.initFromInstance(address);
}
else if (typeof address === 'string') {
this.initFromString(address);
}
else {
throw new Error(`Incorrect address format specified: ` +
`it must be either Address instance or string`);
}
}
static isValid(anyForm) {
try {
new Address(anyForm);
return true;
}
catch (error) {
return false;
}
}
toString(isUserFriendly = this.isUserFriendly, isUrlSafe = this.isUrlSafe, isBounceable = this.isBounceable, isTestOnly = this.isTestOnly) {
if (!isUserFriendly) {
return this.wc + ':' + (0, common_1.bytesToHex)(this.hashPart);
}
else {
let tag = (isBounceable
? Flags.Bounceable
: Flags.NonBounceable);
if (isTestOnly) {
tag |= Flags.Test;
}
const address = new Int8Array(34);
address[0] = tag;
address[1] = this.wc;
address.set(this.hashPart, 2);
const addressWithChecksum = new Uint8Array(36);
addressWithChecksum.set(address);
addressWithChecksum.set((0, common_1.crc16)(address), 34);
let addressBase64 = (0, base64_1.bytesToBase64)(addressWithChecksum);
if (isUrlSafe) {
addressBase64 = addressBase64
.replace(/\+/g, '-')
.replace(/\//g, '_');
}
return addressBase64;
}
}
/**
* Copies the address data from the specified Address
* instance to this instance.
*/
initFromInstance(address) {
this.wc = address.wc;
this.hashPart = address.hashPart;
this.isUserFriendly = address.isUserFriendly;
this.isUrlSafe = address.isUrlSafe;
this.isBounceable = address.isBounceable;
this.isTestOnly = address.isTestOnly;
}
initFromString(addressStr) {
if (addressStr.includes(':')) {
// Non user-friendly address.
// -----
const parts = addressStr.split(':');
if (parts.length !== 2) {
throw new Error(`Invalid address: ${addressStr}, ` +
`non-user-friendly address must contain ` +
`only a single colon`);
}
const workchain = parseInt(parts[0], 10);
this.checkWorkchainOrThrow(workchain);
const hex = parts[1];
if (hex.length !== 64) {
throw new Error(`Invalid address HEX: ${addressStr}`);
}
this.isUserFriendly = false;
this.wc = workchain;
this.hashPart = (0, common_1.hexToBytes)(hex);
this.isUrlSafe = false;
this.isTestOnly = false;
this.isBounceable = false;
}
else {
// User-friendly address.
// -----
const parseResult = (this.parseFriendlyAddress(addressStr));
this.wc = parseResult.workchain;
this.hashPart = parseResult.hashPart;
this.isUserFriendly = true;
this.isUrlSafe = parseResult.isUrlSafe;
this.isBounceable = parseResult.isBounceable;
this.isTestOnly = parseResult.isTestOnly;
}
}
parseFriendlyAddress(addressString) {
// This check is important, because base64 decoding
// process could ignore one extra character at the
// end of string and the byte-length check below
// won't be able to catch it.
if (addressString.length !== 48) {
throw new Error(`User-friendly address should contain ` +
`strictly 48 characters`);
}
const isUrlSafe = (addressString.includes('-') ||
addressString.includes('_'));
if (isUrlSafe) {
addressString = addressString
.replace(/-/g, '+')
.replace(/_/g, '\/');
}
const data = (0, base64_1.base64ToBytes)(addressString);
// SLICING BYTES
//
// • 1B — tag
// • 1B — workchain
// • 32B — hash
// • 2B — CRC
//
// -----
if (data.length !== 36) {
throw new Error(`Incorrect address format: byte length must be ` +
`equal to 36`);
}
const address = data.slice(0, 34);
const hashPart = data.slice(2, 34);
const crc = data.slice(34, 36);
// CRC verification
const checkCrc = (0, common_1.crc16)(address);
if (checkCrc[0] !== crc[0] ||
checkCrc[1] !== crc[1]) {
throw new Error('Wrong CRC-16 checksum');
}
// Tag
let tag = address[0];
let isTestOnly = false;
if (tag & Flags.Test) {
isTestOnly = true;
tag = (tag ^ Flags.Test);
}
if ((tag !== Flags.Bounceable) &&
(tag !== Flags.NonBounceable)) {
throw new Error('Unknown address tag');
}
// Workchain
// @todo: we should read signed integer here
const workchain = (address[1] === 0xff ? -1 : address[1]);
this.checkWorkchainOrThrow(workchain);
return {
workchain,
hashPart,
isUrlSafe,
isBounceable: (tag === Flags.Bounceable),
isTestOnly,
};
}
checkWorkchainOrThrow(workchain) {
if (workchain !== workchain_1.WorkchainId.Master &&
workchain !== workchain_1.WorkchainId.Basic) {
throw new Error(`Invalid address workchain: ${workchain}, ` +
`it must be either -1 or 0`);
}
}
}
exports.Address = Address;
//# sourceMappingURL=address.js.map