UNPKG

@safik/fk-plug-controller

Version:

Internet Computer Plug wallet's controller

272 lines (271 loc) 13.9 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 principal_1 = require("@dfinity/principal"); const fk_dab_js_1 = require("@safik/fk-dab-js"); const random_color_1 = __importDefault(require("random-color")); const errors_1 = require("../errors"); const utils_1 = require("../PlugKeyRing/utils"); const account_1 = require("../utils/account"); const dfx_1 = require("../utils/dfx"); const token_1 = require("../utils/dfx/token"); const rosetta_1 = require("../utils/dfx/history/rosetta"); const tokens_1 = require("../constants/tokens"); const array_1 = require("../utils/array"); const xtcHistory_1 = require("../utils/dfx/history/xtcHistory"); const cap_1 = require("../utils/dfx/history/cap"); class PlugWallet { constructor({ name, icon, walletNumber, mnemonic, registeredTokens = {}, connectedApps = [], assets = tokens_1.DEFAULT_ASSETS, collections = [], fetch, }) { // TODO: Make generic when standard is adopted. Just supports ICPunks rn. this.getNFTs = (refresh) => __awaiter(this, void 0, void 0, function* () { try { this.collections = yield (0, fk_dab_js_1.getCachedUserNFTs)({ userPID: this.principal, refresh, }); return this.collections; } catch (e) { return null; } }); this.transferNFT = (args) => __awaiter(this, void 0, void 0, function* () { const { token, to } = args; if (!(0, utils_1.validatePrincipalId)(to)) { throw new Error(errors_1.ERRORS.INVALID_PRINCIPAL_ID); } const { secretKey } = this.identity.getKeyPair(); const agent = yield (0, dfx_1.createAgent)({ secretKey, fetch: this.fetch }); try { const NFT = (0, fk_dab_js_1.getNFTActor)({ canisterId: token.canister, agent, standard: token.standard, }); yield NFT.transfer(principal_1.Principal.fromText(to), parseInt(token.index.toString(), 10)); // Optimistically update the state const collections = this.collections.map(col => (Object.assign(Object.assign({}, col), { tokens: col.tokens.filter(tok => tok.id !== token.id) }))); this.collections = collections.filter(col => col.tokens.length); (0, fk_dab_js_1.getCachedUserNFTs)({ userPID: this.principal, refresh: true }).catch(console.warn); return this.collections; } catch (e) { throw new Error(errors_1.ERRORS.TRANSFER_NFT_ERROR); } }); this.registerToken = (canisterId, standard = 'ext') => __awaiter(this, void 0, void 0, function* () { if (!(0, utils_1.validateCanisterId)(canisterId)) { throw new Error(errors_1.ERRORS.INVALID_CANISTER_ID); } const { secretKey } = this.identity.getKeyPair(); const agent = yield (0, dfx_1.createAgent)({ secretKey, fetch: this.fetch }); const tokenActor = yield (0, token_1.createTokenActor)(canisterId, agent, standard); const metadata = yield tokenActor.getMetadata(); if (!('fungible' in metadata)) { throw new Error(errors_1.ERRORS.NON_FUNGIBLE_TOKEN_NOT_SUPPORTED); } const color = (0, random_color_1.default)({ luminosity: 'light' }); const tokenDescriptor = Object.assign(Object.assign({}, metadata.fungible), { canisterId, color, standard }); const newTokens = Object.assign(Object.assign({}, this.registeredTokens), { [canisterId]: tokenDescriptor }); // const unique = uniqueByObjKey(newTokens, 'symbol') as StandardToken[]; this.registeredTokens = newTokens; return Object.values(newTokens); }); this.toJSON = () => ({ name: this.name, walletNumber: this.walletNumber, principal: this.identity.getPrincipal().toText(), accountId: this.accountId, icon: this.icon, registeredTokens: this.registeredTokens, connectedApps: this.connectedApps, assets: this.assets.map(asset => (Object.assign(Object.assign({}, asset), { amount: asset.amount.toString() }))), nftCollections: this.collections.map(collection => (Object.assign(Object.assign({}, collection), { tokens: collection.tokens.map(token => (Object.assign(Object.assign({}, token), { index: parseInt(token.index.toString(), 10) }))) }))), }); this.burnXTC = (to, amount) => __awaiter(this, void 0, void 0, function* () { if (!(0, utils_1.validateCanisterId)(to)) { throw new Error(errors_1.ERRORS.INVALID_CANISTER_ID); } const { secretKey } = this.identity.getKeyPair(); const agent = yield (0, dfx_1.createAgent)({ secretKey, fetch: this.fetch }); const xtcActor = yield (0, token_1.createTokenActor)(tokens_1.TOKENS.XTC.canisterId, agent, 'xtc'); const burnResult = yield xtcActor.burnXTC({ to: principal_1.Principal.fromText(to), amount, }); try { if ('Ok' in burnResult) { const trxId = burnResult.Ok; yield (0, xtcHistory_1.requestCacheUpdate)(this.principal, [trxId]); } } catch (e) { console.log('Kyasshu error'); } return burnResult; }); this.getBalance = () => __awaiter(this, void 0, void 0, function* () { const { secretKey } = this.identity.getKeyPair(); // Get ICP Balance const agent = yield (0, dfx_1.createAgent)({ secretKey, fetch: this.fetch }); const ledger = yield (0, dfx_1.createLedgerActor)(agent); const icpBalance = yield ledger.getBalance(this.accountId); // Add XTC if it was not in the first place (backwards compatibility) this.registeredTokens[tokens_1.TOKENS.XTC.canisterId] = tokens_1.TOKENS.XTC; // Get Custom Token Balances const tokenBalances = yield Promise.all(Object.values(this.registeredTokens).map((token) => __awaiter(this, void 0, void 0, function* () { const tokenActor = yield (0, token_1.createTokenActor)(token.canisterId, agent, token.standard); const balance = yield tokenActor.getBalance(this.identity.getPrincipal()); return { name: token.name, symbol: token.symbol, amount: (0, token_1.parseBalance)(balance), canisterId: token.canisterId, }; }))); const assets = [ { name: 'ICP', symbol: 'ICP', amount: (0, token_1.parseBalance)(icpBalance), canisterId: null, }, ...tokenBalances, ]; this.assets = assets; return assets; }); this.getTokenInfo = (canisterId, standard = 'ext') => __awaiter(this, void 0, void 0, function* () { var _a; const { secretKey } = this.identity.getKeyPair(); if (!(0, utils_1.validateCanisterId)(canisterId)) { throw new Error(errors_1.ERRORS.INVALID_CANISTER_ID); } const agent = yield (0, dfx_1.createAgent)({ secretKey, fetch: this.fetch }); const savedStandard = ((_a = this.registeredTokens[canisterId]) === null || _a === void 0 ? void 0 : _a.standard) || standard; const tokenActor = yield (0, token_1.createTokenActor)(canisterId, agent, savedStandard); const metadataResult = yield tokenActor.getMetadata(); const metadata = metadataResult; if (!('fungible' in metadata)) { throw new Error(errors_1.ERRORS.NON_FUNGIBLE_TOKEN_NOT_SUPPORTED); } const tokenBalance = yield tokenActor.getBalance(this.identity.getPrincipal()); const token = Object.assign(Object.assign({}, metadata.fungible), { canisterId, standard: savedStandard }); return { token, amount: (0, token_1.parseBalance)(tokenBalance) }; }); this.getTransactions = () => __awaiter(this, void 0, void 0, function* () { const icpTrxs = yield (0, rosetta_1.getICPTransactions)(this.accountId); const xtcTransactions = yield (0, xtcHistory_1.getXTCTransactions)(this.principal); const capTransactions = yield (0, cap_1.getCapTransactions)(this.principal); // merge and format all trx. sort by timestamp // TODO: any custom token impelmenting archive should be queried. (0.4.0) const transactions = { total: icpTrxs.total + xtcTransactions.total + capTransactions.total, transactions: [ ...capTransactions.transactions, ...icpTrxs.transactions, ...xtcTransactions.transactions, ].sort((a, b) => (b.timestamp - a.timestamp < 0 ? -1 : 1)), }; return transactions; }); this.send = (to, amount, canisterId, opts) => __awaiter(this, void 0, void 0, function* () { return canisterId ? this.sendCustomToken(to, amount, canisterId) : { height: yield this.sendICP(to, amount, opts) }; }); this.addConnectedApp = (app) => { if (!app.url || !app.name || !app.icon || !app.whitelist.every(item => (0, utils_1.validateCanisterId)(item))) { throw new Error(errors_1.ERRORS.INVALID_APP); } this.connectedApps = (0, array_1.uniqueByObjKey)([...this.connectedApps, app], 'url'); return this.connectedApps; }; this.deleteConnectedApp = (url) => { if (!this.connectedApps.some(app => app.url === url)) { return this.connectedApps; } this.connectedApps = [...this.connectedApps.filter(app => app.url !== url)]; return this.connectedApps; }; this.name = name || 'Account 1'; this.icon = icon; this.walletNumber = walletNumber; this.assets = assets; this.registeredTokens = (0, token_1.formatStorageTokens)(Object.assign(Object.assign({}, registeredTokens), { [tokens_1.TOKENS.XTC.canisterId]: tokens_1.TOKENS.XTC })); const { identity, accountId } = (0, account_1.createAccountFromMnemonic)(mnemonic, walletNumber); this.identity = identity; this.accountId = accountId; this.principal = identity.getPrincipal().toText(); this.connectedApps = [...connectedApps]; this.collections = [...collections]; this.fetch = fetch; } setName(val) { this.name = val; } sign(payload) { return __awaiter(this, void 0, void 0, function* () { return this.identity.sign(payload); }); } setIcon(val) { this.icon = val; } get publicKey() { return this.identity.getKeyPair().publicKey; } get pemFile() { return this.identity.getPem(); } sendICP(to, amount, opts) { return __awaiter(this, void 0, void 0, function* () { const { secretKey } = this.identity.getKeyPair(); const agent = yield (0, dfx_1.createAgent)({ secretKey, fetch: this.fetch }); const ledger = yield (0, dfx_1.createLedgerActor)(agent); return ledger.sendICP({ to, amount, opts }); }); } sendCustomToken(to, amount, canisterId) { return __awaiter(this, void 0, void 0, function* () { const { secretKey } = this.identity.getKeyPair(); const agent = yield (0, dfx_1.createAgent)({ secretKey, fetch: this.fetch }); const savedToken = this.registeredTokens[canisterId]; const tokenActor = yield (0, token_1.createTokenActor)(canisterId, agent, savedToken.standard); const result = yield tokenActor.send({ to, from: this.identity.getPrincipal().toString(), amount, }); if (canisterId === tokens_1.TOKENS.XTC.canisterId) { try { if ('transactionId' in result) { const trxId = result.transactionId; yield (0, xtcHistory_1.requestCacheUpdate)(this.principal, [BigInt(trxId)]); } } catch (e) { console.log('Kyasshu error', e); } } return result; }); } } exports.default = PlugWallet;