UNPKG

@safik/fk-plug-controller

Version:

Internet Computer Plug wallet's controller

289 lines (288 loc) 15.1 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const crypto_js_1 = __importDefault(require("crypto-js")); const principal_1 = require("@dfinity/principal"); const json_bigint_1 = __importDefault(require("json-bigint")); const errors_1 = require("../errors"); const PlugWallet_1 = __importDefault(require("../PlugWallet")); const account_1 = require("../utils/account"); const storage_1 = __importDefault(require("../utils/storage")); const utils_1 = require("./utils"); const object_1 = require("../utils/object"); class PlugKeyRing { constructor(StorageAdapter = new storage_1.default(), CryptoAdapter = crypto_js_1.default, FetchAdapter) { this.isUnlocked = false; this.isInitialized = false; this.init = () => __awaiter(this, void 0, void 0, function* () { const state = (yield this.storage.get()); this.isUnlocked = !!(state === null || state === void 0 ? void 0 : state.isUnlocked); this.isInitialized = !!(state === null || state === void 0 ? void 0 : state.isInitialized); this.currentWalletId = (state === null || state === void 0 ? void 0 : state.currentWalletId) || 0; }); this.getPublicKey = (subAccount) => __awaiter(this, void 0, void 0, function* () { yield this.checkInitialized(); const index = (subAccount !== null && subAccount !== void 0 ? subAccount : this.currentWalletId) || 0; this.validateSubaccount(index); const wallet = this.state.wallets[index]; return wallet.publicKey; }); this.getNFTs = (subAccount) => __awaiter(this, void 0, void 0, function* () { this.checkUnlocked(); const index = (subAccount !== null && subAccount !== void 0 ? subAccount : this.currentWalletId) || 0; const { wallets } = this.state; this.validateSubaccount(index); const wallet = wallets[index]; const nfts = yield wallet.getNFTs(); wallets.splice(index, 1, wallet); this.state.wallets = wallets; yield this.saveEncryptedState({ wallets }, this.state.password); return nfts; }); this.transferNFT = ({ subAccount, token, to, }) => __awaiter(this, void 0, void 0, function* () { this.checkUnlocked(); const index = (subAccount !== null && subAccount !== void 0 ? subAccount : this.currentWalletId) || 0; const { wallets } = this.state; this.validateSubaccount(index); const wallet = wallets[index]; const collections = yield wallet.transferNFT({ token, to }); wallets.splice(index, 1, wallet); this.state.wallets = wallets; yield this.saveEncryptedState({ wallets }, this.state.password); return collections; }); this.loadFromPersistance = (password) => __awaiter(this, void 0, void 0, function* () { const { vault, isInitialized, currentWalletId, } = ((yield this.storage.get()) || {}); if (isInitialized && vault) { const decrypted = this.decryptState(vault, password); const wallets = decrypted.wallets.map(wallet => new PlugWallet_1.default(Object.assign(Object.assign({}, wallet), { mnemonic: decrypted.mnemonic, fetch: this.fetch }))); this.state = Object.assign(Object.assign({}, decrypted), { wallets }); this.isInitialized = isInitialized; this.currentWalletId = currentWalletId; } }); this.burnXTC = ({ to, amount, subAccount, }) => __awaiter(this, void 0, void 0, function* () { this.checkUnlocked(); const index = (subAccount !== null && subAccount !== void 0 ? subAccount : this.currentWalletId) || 0; const { wallets } = this.state; this.validateSubaccount(index); const wallet = wallets[index]; return wallet.burnXTC(to, amount); }); this.create = ({ password = '', icon, name, entropy, }) => __awaiter(this, void 0, void 0, function* () { const { mnemonic } = (0, account_1.createAccount)(entropy); const wallet = yield this.createAndPersistKeyRing({ mnemonic, password, icon, name, }); return { wallet, mnemonic }; }); this.importMnemonic = ({ mnemonic, password, }) => __awaiter(this, void 0, void 0, function* () { const wallet = yield this.createAndPersistKeyRing({ mnemonic, password }); return { wallet, mnemonic }; }); // Assumes the state is already initialized this.createPrincipal = (opts) => __awaiter(this, void 0, void 0, function* () { yield this.checkInitialized(); this.checkUnlocked(); const wallet = new PlugWallet_1.default(Object.assign(Object.assign({}, opts), { mnemonic: this.state.mnemonic, walletNumber: this.state.wallets.length, fetch: this.fetch })); const wallets = [...this.state.wallets, wallet]; yield this.saveEncryptedState({ wallets }, this.state.password); this.state.wallets = wallets; return wallet; }); this.setCurrentPrincipal = (walletNumber) => __awaiter(this, void 0, void 0, function* () { yield this.checkInitialized(); this.validateSubaccount(walletNumber); this.currentWalletId = walletNumber; yield this.storage.set({ currentWalletId: walletNumber }); }); this.getState = () => __awaiter(this, void 0, void 0, function* () { yield this.checkInitialized(); this.checkUnlocked(); return (0, object_1.recursiveParseBigint)(Object.assign(Object.assign({}, this.state), { currentWalletId: this.currentWalletId })); }); this.sign = (payload, subAccount) => __awaiter(this, void 0, void 0, function* () { this.checkUnlocked(); const index = (subAccount !== null && subAccount !== void 0 ? subAccount : this.currentWalletId) || 0; this.validateSubaccount(index); const wallet = this.state.wallets[index]; const signed = yield wallet.sign(payload); return signed; }); this.unlock = (password) => __awaiter(this, void 0, void 0, function* () { var _a; yield this.checkInitialized(); try { yield this.loadFromPersistance(password); this.isUnlocked = password === ((_a = this.state) === null || _a === void 0 ? void 0 : _a.password); yield this.storage.set({ isUnlocked: this.isUnlocked }); return this.isUnlocked; } catch (e) { this.isUnlocked = false; return false; } }); this.lock = () => __awaiter(this, void 0, void 0, function* () { this.isUnlocked = false; this.state = { wallets: [] }; yield this.storage.set({ isUnlocked: this.isUnlocked }); }); this.editPrincipal = (walletNumber, { name, emoji }) => __awaiter(this, void 0, void 0, function* () { yield this.checkInitialized(); this.checkUnlocked(); this.validateSubaccount(walletNumber); const wallet = this.state.wallets[walletNumber]; if (name) wallet.setName(name); if (emoji) wallet.setIcon(emoji); const { wallets } = this.state; wallets.splice(walletNumber, 1, wallet); this.state.wallets = wallets; this.saveEncryptedState({ wallets }, this.state.password); }); this.registerToken = (canisterId, standard = 'ext', subAccount) => __awaiter(this, void 0, void 0, function* () { this.checkUnlocked(); const index = (subAccount !== null && subAccount !== void 0 ? subAccount : this.currentWalletId) || 0; const { wallets } = this.state; this.validateSubaccount(index); const wallet = wallets[index]; const registeredTokens = yield wallet.registerToken(canisterId, standard); wallets.splice(index, 1, wallet); this.state.wallets = wallets; yield this.saveEncryptedState({ wallets }, this.state.password); return registeredTokens; }); this.getBalance = (subAccount) => __awaiter(this, void 0, void 0, function* () { this.checkUnlocked(); const index = (subAccount !== null && subAccount !== void 0 ? subAccount : this.currentWalletId) || 0; this.validateSubaccount(index); return this.state.wallets[index].getBalance(); }); this.getTokenInfo = (canisterId, standard = 'ext', subAccount) => __awaiter(this, void 0, void 0, function* () { this.checkUnlocked(); const index = (subAccount !== null && subAccount !== void 0 ? subAccount : this.currentWalletId) || 0; this.validateSubaccount(index); return this.state.wallets[index].getTokenInfo(canisterId, standard); }); this.getTransactions = (subAccount) => __awaiter(this, void 0, void 0, function* () { this.checkUnlocked(); const index = (subAccount !== null && subAccount !== void 0 ? subAccount : this.currentWalletId) || 0; this.validateSubaccount(index); return this.state.wallets[index].getTransactions(); }); this.checkInitialized = () => __awaiter(this, void 0, void 0, function* () { yield this.init(); if (!this.isInitialized) throw new Error(errors_1.ERRORS.NOT_INITIALIZED); }); this.send = (to, amount, canisterId, opts) => __awaiter(this, void 0, void 0, function* () { this.checkUnlocked(); const currentWalletNumber = this.currentWalletId; let account = to; if (!canisterId && (0, utils_1.validatePrincipalId)(to)) { account = (0, account_1.getAccountId)(principal_1.Principal.fromText(to)); } return this.state.wallets[currentWalletNumber || 0].send(account, amount, canisterId, opts); }); this.addConnectedApp = (app, subAccount) => __awaiter(this, void 0, void 0, function* () { this.checkUnlocked(); const index = (subAccount !== null && subAccount !== void 0 ? subAccount : this.currentWalletId) || 0; this.validateSubaccount(index); const { wallets } = this.state; const wallet = wallets[index]; const apps = wallet.addConnectedApp(app); this.state.wallets = wallets; yield this.saveEncryptedState({ wallets }, this.state.password); return apps; }); this.deleteConnectedApp = (id, subAccount) => __awaiter(this, void 0, void 0, function* () { this.checkUnlocked(); const index = (subAccount !== null && subAccount !== void 0 ? subAccount : this.currentWalletId) || 0; this.validateSubaccount(index); const { wallets } = this.state; const wallet = wallets[index]; const apps = wallet.deleteConnectedApp(id); this.state.wallets = wallets; yield this.saveEncryptedState({ wallets }, this.state.password); return apps; }); this.getPemFile = (walletNumber) => { this.checkUnlocked(); const currentWalletNumber = (walletNumber !== null && walletNumber !== void 0 ? walletNumber : this.currentWalletId) || 0; this.validateSubaccount(currentWalletNumber); return this.state.wallets[currentWalletNumber].pemFile; }; this.checkUnlocked = () => { if (!this.isUnlocked) { throw new Error(errors_1.ERRORS.STATE_LOCKED); } }; this.createAndPersistKeyRing = ({ mnemonic, password, icon, name, }) => __awaiter(this, void 0, void 0, function* () { if (!password) throw new Error(errors_1.ERRORS.PASSWORD_REQUIRED); const wallet = new PlugWallet_1.default({ icon, name, mnemonic, walletNumber: 0, fetch: this.fetch, }); const data = { wallets: [wallet.toJSON()], password, mnemonic, }; this.isInitialized = true; this.currentWalletId = 0; yield this.storage.clear(); yield this.storage.set({ isInitialized: true, isUnlocked: false, currentWalletId: 0, }); yield this.saveEncryptedState(data, password); return wallet; }); this.saveEncryptedState = (newState, password) => __awaiter(this, void 0, void 0, function* () { const stringData = json_bigint_1.default.stringify(Object.assign(Object.assign({}, this.state), newState)); const encrypted = this.crypto.AES.encrypt(stringData, password); yield this.storage.set({ vault: encrypted.toString() }); }); this.decryptState = (state, password) => JSON.parse(this.crypto.AES.decrypt(state, password).toString(this.crypto.enc.Utf8)); this.state = { wallets: [] }; this.isUnlocked = false; this.isInitialized = false; this.currentWalletId = 0; this.storage = StorageAdapter; this.crypto = CryptoAdapter; this.fetch = FetchAdapter; } validateSubaccount(subaccount) { if (subaccount < 0 || !Number.isInteger(subaccount) || subaccount >= (this.state.wallets.length || 0)) { throw new Error(errors_1.ERRORS.INVALID_WALLET_NUMBER); } } get currentWallet() { this.checkUnlocked(); return this.state.wallets[this.currentWalletId || 0]; } } exports.default = PlugKeyRing;