chaingate
Version:
Multi-chain cryptocurrency SDK for TypeScript — unified API for Bitcoin, Ethereum, Litecoin, Dogecoin, Bitcoin Cash, Polygon, Arbitrum, and any EVM-compatible chain. Create wallets, query balances, send transactions, and manage tokens and NFTs across UTXO
141 lines (140 loc) • 4.97 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Phrase = void 0;
const bip39_1 = require("@scure/bip39");
const czech_js_1 = require("@scure/bip39/wordlists/czech.js");
const english_js_1 = require("@scure/bip39/wordlists/english.js");
const french_js_1 = require("@scure/bip39/wordlists/french.js");
const italian_js_1 = require("@scure/bip39/wordlists/italian.js");
const japanese_js_1 = require("@scure/bip39/wordlists/japanese.js");
const korean_js_1 = require("@scure/bip39/wordlists/korean.js");
const portuguese_js_1 = require("@scure/bip39/wordlists/portuguese.js");
const simplified_chinese_js_1 = require("@scure/bip39/wordlists/simplified-chinese.js");
const spanish_js_1 = require("@scure/bip39/wordlists/spanish.js");
// Local copy — @scure/bip39@2.0.1 has a broken exports map for this wordlist
const traditional_chinese_1 = require("../../../../wordlists/traditional-chinese");
const Secret_1 = require("../../../Secret");
const utils_1 = require("../../../../utils");
const Seed_1 = require("../SeedWallet/Seed");
const errors_1 = require("../../../errors");
const wordlists = {
czech: czech_js_1.wordlist,
english: english_js_1.wordlist,
french: french_js_1.wordlist,
italian: italian_js_1.wordlist,
japanese: japanese_js_1.wordlist,
korean: korean_js_1.wordlist,
portuguese: portuguese_js_1.wordlist,
simplifiedChinese: simplified_chinese_js_1.wordlist,
spanish: spanish_js_1.wordlist,
traditionalChinese: traditional_chinese_1.wordlist,
};
// Build a reverse lookup: word -> Set of language names
const wordToLanguages = new Map();
for (const [lang, wl] of Object.entries(wordlists)) {
for (const word of wl) {
let langs = wordToLanguages.get(word);
if (!langs) {
langs = new Set();
wordToLanguages.set(word, langs);
}
langs.add(lang);
}
}
const VALID_WORD_COUNTS = [12, 15, 18, 21, 24];
const WORDS_TO_STRENGTH = {
12: 128,
15: 160,
18: 192,
21: 224,
24: 256,
};
/**
* A mnemonic phrase (e.g. 12 or 24 words). Supports encryption and multi-language mnemonics.
*
* @example
* ```ts
* const phrase = Phrase.new('english', 12);
* const phrase = new Phrase('abandon abandon ... about');
* ```
*/
class Phrase extends Secret_1.Secret {
/**
* @param phrase - A mnemonic string or {@link EncryptedState}.
* @throws {@link InvalidPhraseError} if the mnemonic is invalid.
*/
constructor(phrase) {
if (typeof phrase === 'object') {
super(phrase);
}
else {
Phrase.validate(phrase);
super(new TextEncoder().encode(phrase.trim()));
}
}
get phrase() {
return new TextDecoder().decode(this.data);
}
/** The mnemonic as raw bytes. */
get raw() {
return this.data;
}
/** The mnemonic as hex. */
get hex() {
return (0, utils_1.bytesToHex)(this.data);
}
/** The individual words of the mnemonic phrase. */
get words() {
return this.phrase.split(/\s+/);
}
/** Converts this mnemonic to a {@link Seed}. */
getSeed() {
return new Seed_1.Seed((0, bip39_1.mnemonicToSeedSync)(this.phrase));
}
/**
* Generates a new random mnemonic phrase.
*
* @param language - Wordlist language. Defaults to `'english'`.
* @param numberOfWords - Number of words. Defaults to `12`.
*/
static new(language = 'english', numberOfWords = 12) {
const wordlist = wordlists[language];
const strength = WORDS_TO_STRENGTH[numberOfWords];
const mnemonic = (0, bip39_1.generateMnemonic)(wordlist, strength);
return new Phrase(mnemonic);
}
/**
* Checks whether a string is a valid mnemonic phrase (any supported language).
*
* @param phrase - The string to validate.
*/
static isValid(phrase) {
try {
Phrase.validate(phrase);
return true;
}
catch {
return false;
}
}
static validate(phrase) {
const trimmed = phrase.trim();
if (!trimmed)
throw new errors_1.InvalidPhraseError('Mnemonic phrase is empty');
const words = trimmed.split(/\s+/);
if (!VALID_WORD_COUNTS.includes(words.length)) {
throw new errors_1.InvalidPhraseError(`Mnemonic must be ${VALID_WORD_COUNTS.join(', ')} words, got ${words.length}`);
}
// Detect candidate languages from the first word to narrow the search
const firstWord = words[0];
const candidateLangs = wordToLanguages.get(firstWord);
if (candidateLangs) {
for (const lang of candidateLangs) {
if ((0, bip39_1.validateMnemonic)(trimmed, wordlists[lang]))
return;
}
}
throw new errors_1.InvalidPhraseError('Invalid mnemonic phrase');
}
}
exports.Phrase = Phrase;