UNPKG

@ton.js/core

Version:

TonWeb - JavaScript API for TON blockchain

183 lines 6.56 kB
"use strict"; 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