UNPKG

machinomy

Version:

Micropayments powered by Ethereum

204 lines 8.8 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; Object.defineProperty(exports, "__esModule", { value: true }); const MigrateOption_1 = require("./MigrateOption"); const BigNumber = require("bignumber.js"); const payment_1 = require("./payment"); const accept_payment_request_1 = require("./accept_payment_request"); const Registry_1 = require("./Registry"); const MachinomyOptions_1 = require("./MachinomyOptions"); const decko_1 = require("decko"); /** * Machinomy is a library for micropayments in Ether over HTTP. * Machinomy provides API to send and receive a minuscule amount of money instantly. * Core method is [buy]{@link Machinomy.buy}. The method does all the heavy lifting providing an easy interface * for micropayments. * * See [examples](https://github.com/machinomy/machinomy/tree/master/examples) directory for both client and server sides. * * NB. All monetary values below are denominated in Wei, including: [buy]{@link Machinomy.buy} and * [deposit]{@link Machinomy.deposit} methods. */ class Machinomy { constructor(account, web3, options) { this.migrated = false; this.account = account; let _options = MachinomyOptions_1.default.defaults(options); this.registry = new Registry_1.default(account, web3, _options); } /** * Entrypoint for a purchasing. * * Wnen you `buy` for the first time from the same receiver, the method opens a channel with a deposit equal to `price`✕10. * Next method call forms a payment and sends it via http to `gateway` url. * * The method then returns a token and channel id, in form of {@link BuyResult}. * * @example * <pre><code>machinomy.buy({ * receiver: receiver, // address * price: 100, * gateway: 'http://localhost:3001/machinomy' * }) * </code></pre> */ async buy(options) { await this.checkMigrationsState(); if (!options.gateway) { throw new Error('gateway must be specified.'); } let client = await this.registry.client(); let channelManager = await this.registry.channelManager(); const payment = await this.nextPayment(options); const res = await client.doPayment(payment, options.gateway, options.purchaseMeta); await channelManager.spendChannel(payment, res.token); return { token: res.token, channelId: payment.channelId }; } async payment(options) { await this.checkMigrationsState(); let channelManager = await this.registry.channelManager(); const payment = await this.nextPayment(options); await channelManager.spendChannel(payment); return { payment: payment_1.PaymentSerde.instance.serialize(payment) }; } async pry(uri, datetime) { await this.checkMigrationsState(); let client = await this.registry.client(); return client.doPreflight(this.account, uri, datetime); } async buyUrl(uri) { await this.checkMigrationsState(); let client = await this.registry.client(); let req = await client.doPreflight(this.account, uri); return this.buy({ receiver: req.receiver, price: req.price, gateway: req.gateway, meta: req.meta, tokenContract: req.tokenContract }); } /** * Put more money into the channel. * * @example * <pre><code> * let channelId = '0x0bf080aeb3ed7ea6f9174d804bd242f0b31ff1ea24800344abb580cd87f61ca7' * machinomy.deposit(channelId, web3.toWei(1, "ether").toNumber(())) // Put 1 Ether more * </code></pre> * * @param channelId - Channel id. * @param value - Size of deposit in Wei. */ async deposit(channelId, value) { await this.checkMigrationsState(); const _value = new BigNumber.BigNumber(value); let channelManager = await this.registry.channelManager(); return channelManager.deposit(channelId, _value); } async open(receiver, value, channelId, tokenContract) { await this.checkMigrationsState(); const _value = new BigNumber.BigNumber(value); let channelManager = await this.registry.channelManager(); return channelManager.openChannel(this.account, receiver, _value, new BigNumber.BigNumber(0), channelId, tokenContract); } /** * Returns the list of opened channels. */ async channels() { await this.checkMigrationsState(); let channelManager = await this.registry.channelManager(); return channelManager.channels(); } async openChannels() { await this.checkMigrationsState(); let channelManager = await this.registry.channelManager(); return channelManager.openChannels(); } async settlingChannels() { await this.checkMigrationsState(); let channelManager = await this.registry.channelManager(); return channelManager.settlingChannels(); } async channelById(channelId) { await this.checkMigrationsState(); let channelManager = await this.registry.channelManager(); return channelManager.channelById(channelId); } /** * Share the money between sender and reciver according to payments made. * * For example a channel was opened with 10 Ether. Sender makes 6 purchases, 1 Ether each. * Total value transferred is 6 Ether. * If a party closes the channel, the money deposited to the channel are split. * The receiver gets 6 Ether. 4 unspent Ethers return to the sender. * * A channel can be closed in two ways, according to what party initiates that. * The method nicely abstracts over that, so you do not need to know what is really going on under the hood. * For more details on how payment channels work refer to a website. */ async close(channelId) { await this.checkMigrationsState(); let channelManager = await this.registry.channelManager(); return channelManager.closeChannel(channelId); } /** * Save payment into the storage and return an id of the payment. The id can be used by {@link Machinomy.paymentById}. */ async acceptPayment(req) { await this.checkMigrationsState(); let client = await this.registry.client(); return client.acceptPayment(accept_payment_request_1.AcceptPaymentRequestSerde.instance.deserialize(req)); } /** * Return information about the payment by id. */ async paymentById(id) { await this.checkMigrationsState(); let storage = await this.registry.storage(); return storage.paymentsDatabase.findByToken(id); } async acceptToken(req) { await this.checkMigrationsState(); let client = await this.registry.client(); return client.acceptVerify(req); } async shutdown() { await this.checkMigrationsState(); let storage = await this.registry.storage(); return storage.engine.close(); } async nextPayment(options) { await this.checkMigrationsState(); const price = new BigNumber.BigNumber(options.price); let channelManager = await this.registry.channelManager(); const channel = await channelManager.requireOpenChannel(this.account, options.receiver, price, undefined, options.tokenContract); return channelManager.nextPayment(channel.channelId, price, options.meta || ''); } async checkMigrationsState() { if (this.migrated) return; let storage = await this.registry.storage(); let isLatest = await storage.migrator.isLatest(); let needMigration = !isLatest; if (needMigration) { if (this.registry.options.migrate === undefined || this.registry.options.migrate === MigrateOption_1.MigrateOption.Silent) { this.migrated = true; return storage.migrator.sync(); } else { throw new Error('There are non-applied db-migrations!'); } } } } __decorate([ decko_1.memoize ], Machinomy.prototype, "checkMigrationsState", null); exports.default = Machinomy; //# sourceMappingURL=Machinomy.js.map