UNPKG

nano-wallet-js-test-1

Version:

SDK for developers to create and interact with Nanocurrency wallet easily

225 lines (224 loc) 7.77 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const nanocurrency_1 = require("nanocurrency"); const RpcController_1 = __importDefault(require("../rpc/RpcController")); const Constants_1 = require("../Constants"); const BaseController_1 = __importDefault(require("../BaseController")); const utils_1 = require("../utils"); class NanoWallet extends BaseController_1.default { rpc; publicKey; account; defaultConfig = { rpcUrls: [], workerUrls: [], privateKey: null, representative: '', minAmountRaw: (0, nanocurrency_1.convert)(Constants_1.MIN_AMOUNT.toString(), { from: nanocurrency_1.Unit.NANO, to: nanocurrency_1.Unit.raw, }), timeout: Constants_1.DEFAULT_TIMEOUT, }; defaultState = { balance: '0', receivable: '0', receivableBlocks: [], frontier: null, representative: null, }; constructor(config, state) { super(config, state || undefined); this.publicKey = (0, nanocurrency_1.derivePublicKey)(config.privateKey); this.account = (0, nanocurrency_1.deriveAddress)(this.publicKey, { useNanoPrefix: true }); this.rpc = new RpcController_1.default({ rpcUrls: config.rpcUrls, workerUrls: config.workerUrls, timeout: config.timeout, }); this.initialize(); } async sync() { try { const { balance, frontier, receivable, representative } = await this.rpc.accountInfo(this.account); await this.update({ balance, frontier, receivable, representative }); } catch (error) { if (error.message !== 'Account not found') { throw error; } } await this.getReceivable(); } async workGenerate(hash, threshold) { const { work } = await this.rpc.workGenerate(hash, threshold); if (!work) { throw new Error('No work'); } const isValidWork = (0, nanocurrency_1.validateWork)({ work, blockHash: hash, threshold, }); if (!isValidWork) { throw new Error('Invalid work'); } return work; } async getReceivable() { const { blocks = {} } = await this.rpc.receivable(this.account, { threshold: this.config.minAmountRaw, }); let receivableBlocks = []; let receivable = '0'; for (const blockHash in blocks) { receivableBlocks.push({ blockHash, amount: blocks[blockHash], }); receivable = (0, utils_1.TunedBigNumber)(receivable) .plus(blocks[blockHash]) .toString(); } await this.update({ receivableBlocks, receivable }); return { receivableBlocks, receivable }; } async receive(link) { link = link.toUpperCase(); const amount = this.state.receivableBlocks.find(({ blockHash }) => blockHash === link)?.amount; if (!amount) { throw new Error('No receivable block'); } const balance = (0, utils_1.TunedBigNumber)(this.state.balance).plus(amount).toString(); const { block, hash } = (0, nanocurrency_1.createBlock)(this.config.privateKey, { previous: this.state.frontier, representative: this.config.representative, balance, link, work: null, }); const frontier = this.state.frontier || this.publicKey; const work = await this.workGenerate(frontier, Constants_1.RECEIVE_DIFFICULTY); const processed = await this.rpc.process({ ...block, work, }); if (processed.hash !== hash) { throw new Error('Block hash mismatch'); } const receivableBlocks = this.state.receivableBlocks.filter(({ blockHash }) => blockHash !== link); const receivable = (0, utils_1.TunedBigNumber)(this.state.receivable) .minus(amount) .toString(); await this.update({ balance, frontier: hash, receivableBlocks, receivable, }); return { hash }; } async send(to, amount) { if (this.state.frontier === null) { throw new Error('No frontier'); } const balance = (0, utils_1.TunedBigNumber)(this.state.balance).minus(amount).toString(); const { block, hash } = (0, nanocurrency_1.createBlock)(this.config.privateKey, { previous: this.state.frontier, representative: this.config.representative, balance, link: to, work: null, }); const work = await this.workGenerate(this.state.frontier, Constants_1.SEND_DIFFICULTY); const processed = await this.rpc.process({ ...block, work, }); if (processed.hash !== hash) { throw new Error('Block hash mismatch'); } await this.update({ balance, frontier: hash, }); return { hash }; } async sweep(to) { if (this.state.frontier === null) { throw new Error('No frontier'); } const { block, hash } = (0, nanocurrency_1.createBlock)(this.config.privateKey, { previous: this.state.frontier, representative: this.config.representative, balance: '0', link: to, work: null, }); const work = await this.workGenerate(this.state.frontier, Constants_1.SEND_DIFFICULTY); const processed = await this.rpc.process({ ...block, work, }); if (processed.hash !== hash) { throw new Error('Block hash mismatch'); } await this.update({ balance: '0', frontier: hash, }); return { hash }; } async setRepresentative(account) { if (this.state.frontier === null) { throw new Error('No frontier'); } const representative = account || this.config.representative; const { block, hash } = (0, nanocurrency_1.createBlock)(this.config.privateKey, { previous: this.state.frontier, representative, balance: this.state.balance, link: null, work: null, }); const work = await this.workGenerate(this.state.frontier, Constants_1.SEND_DIFFICULTY); const processed = await this.rpc.process({ ...block, work, }); if (processed.hash !== hash) { throw new Error('Block hash mismatch'); } await this.update({ balance: '0', frontier: hash, representative, }); this.configure({ representative, }); return { hash }; } get balance() { return this.state.balance; } get receivable() { return this.state.receivable; } get receivableBlocks() { return this.state.receivableBlocks; } get frontier() { return this.state.frontier; } // Current representative may be different from the initialized representative // if after initialization of instance there has not yet been a new transaction or // .setRepresentative() has not been called yet. get currentRepresentative() { return this.state.representative; } } exports.default = NanoWallet;