UNPKG

@waves/provider-keeper

Version:
315 lines (314 loc) 9.36 kB
var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => { __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; import mitt from "mitt"; import { base58 } from "@scure/base"; import create from "@waves/parse-json-bignumber"; import { TRANSACTION_TYPE } from "@waves/ts-types"; const { parse } = create(); function isAlias(source) { return source.startsWith("alias:"); } function addressFactory(address) { return !isAlias(address) ? address : address.split(":")[2]; } function moneyFactory(amount, assetId = "WAVES") { return { coins: amount, assetId: assetId || "WAVES" }; } function defaultsFactory(tx) { const { fee, senderPublicKey, timestamp } = tx; let feeAssetId; if (tx.type === TRANSACTION_TYPE.TRANSFER || tx.type === TRANSACTION_TYPE.INVOKE_SCRIPT) { ({ feeAssetId } = tx); } return { ...fee ? { fee: moneyFactory(fee, feeAssetId) } : {}, ...senderPublicKey ? { senderPublicKey } : {}, ...timestamp ? { timestamp } : {} }; } function issueAdapter(tx) { const { name, description, quantity, decimals, reissuable, script } = tx; const data = { ...defaultsFactory(tx), name, description: description || "", quantity, precision: decimals, reissuable: reissuable || false, ...script ? { script } : {} }; return { type: TRANSACTION_TYPE.ISSUE, data }; } function transferAdapter(tx) { const { amount, assetId, recipient, attachment } = tx; const data = { ...defaultsFactory(tx), amount: moneyFactory(amount, assetId), recipient: addressFactory(recipient), ...attachment ? { attachment: Array.from(base58.decode(attachment)) } : {} }; return { type: TRANSACTION_TYPE.TRANSFER, data }; } function reissueAdapter(tx) { const { assetId, quantity, reissuable } = tx; const data = { ...defaultsFactory(tx), assetId, quantity, reissuable }; return { type: TRANSACTION_TYPE.REISSUE, data }; } function burnAdapter(tx) { const { assetId, amount } = tx; const data = { ...defaultsFactory(tx), assetId, amount }; return { type: TRANSACTION_TYPE.BURN, data }; } function leaseAdapter(tx) { const { recipient, amount } = tx; const data = { ...defaultsFactory(tx), recipient: addressFactory(recipient), amount }; return { type: TRANSACTION_TYPE.LEASE, data }; } function leaseCancelAdapter(tx) { const { leaseId } = tx; const data = { ...defaultsFactory(tx), leaseId }; return { type: TRANSACTION_TYPE.CANCEL_LEASE, data }; } function aliasAdapter(tx) { const { alias } = tx; const data = { ...defaultsFactory(tx), alias }; return { type: TRANSACTION_TYPE.ALIAS, data }; } function massTransferAdapter(tx) { const { assetId, transfers, attachment } = tx; const data = { ...defaultsFactory(tx), totalAmount: moneyFactory(0, assetId), transfers: transfers.map((transfer) => ({ recipient: addressFactory(transfer.recipient), amount: transfer.amount })), ...attachment ? { attachment: Array.from(base58.decode(attachment)) } : {} }; return { type: TRANSACTION_TYPE.MASS_TRANSFER, data }; } function dataAdapter(tx) { const { data } = tx; const dataTx = { ...defaultsFactory(tx), data }; return { type: TRANSACTION_TYPE.DATA, data: dataTx }; } function setScriptAdapter(tx) { const { script } = tx; const data = { ...defaultsFactory(tx), script }; return { type: TRANSACTION_TYPE.SET_SCRIPT, data }; } function sponsorshipAdapter(tx) { const { assetId, minSponsoredAssetFee } = tx; const data = { ...defaultsFactory(tx), minSponsoredAssetFee: moneyFactory(minSponsoredAssetFee || 0, assetId) }; return { type: TRANSACTION_TYPE.SPONSORSHIP, data }; } function setAssetScriptAdapter(tx) { const { assetId, script } = tx; const data = { ...defaultsFactory(tx), assetId, script }; return { type: TRANSACTION_TYPE.SET_ASSET_SCRIPT, data }; } function invokeScriptAdapter(tx) { const { dApp, payment, call } = tx; const data = { ...defaultsFactory(tx), dApp: addressFactory(dApp), payment: payment || [], ...call ? { call } : {} }; return { type: TRANSACTION_TYPE.INVOKE_SCRIPT, data }; } function keeperTxFactory(tx) { switch (tx.type) { case TRANSACTION_TYPE.ISSUE: return issueAdapter(tx); case TRANSACTION_TYPE.TRANSFER: return transferAdapter(tx); case TRANSACTION_TYPE.REISSUE: return reissueAdapter(tx); case TRANSACTION_TYPE.BURN: return burnAdapter(tx); case TRANSACTION_TYPE.LEASE: return leaseAdapter(tx); case TRANSACTION_TYPE.CANCEL_LEASE: return leaseCancelAdapter(tx); case TRANSACTION_TYPE.ALIAS: return aliasAdapter(tx); case TRANSACTION_TYPE.MASS_TRANSFER: return massTransferAdapter(tx); case TRANSACTION_TYPE.DATA: return dataAdapter(tx); case TRANSACTION_TYPE.SET_SCRIPT: return setScriptAdapter(tx); case TRANSACTION_TYPE.SPONSORSHIP: return sponsorshipAdapter(tx); case TRANSACTION_TYPE.SET_ASSET_SCRIPT: return setAssetScriptAdapter(tx); case TRANSACTION_TYPE.INVOKE_SCRIPT: return invokeScriptAdapter(tx); default: throw new Error("Unsupported transaction type"); } } function signerTxFactory(signed) { return parse(signed); } class ProviderKeeper { constructor() { __publicField(this, "user", null); __publicField(this, "_apiPromise"); __publicField(this, "_connectPromise"); // used in _ensureApi __publicField(this, "_connectResolve"); // initialized in Promise constructor __publicField(this, "_options", { NETWORK_BYTE: "W".charCodeAt(0), NODE_URL: "https://nodes.wavesnodes.com" }); __publicField(this, "_emitter", mitt()); this._apiPromise = isKeeperInstalled().then((isInstalled) => { return isInstalled ? window.WavesKeeper.initialPromise.then((api) => Promise.resolve(api)) : Promise.reject(new Error("WavesKeeper is not installed.")); }); this._apiPromise.catch(() => { }); this._connectPromise = new Promise((resolve) => { this._connectResolve = resolve; }); } on(event, handler) { this._emitter.on(event, handler); return this; } once(event, handler) { const wrappedHandler = (...args) => { handler(...args); this._emitter.off(event, wrappedHandler); }; this._emitter.on(event, wrappedHandler); return this; } off(event, handler) { this._emitter.off(event, handler); return this; } connect(options) { this._options = options; this._connectResolve(); return Promise.resolve(); } login() { return this._ensureApi().then((api) => api.publicState()).then((state) => { this.user = { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion address: state.account.address, // eslint-disable-next-line @typescript-eslint/no-non-null-assertion publicKey: state.account.publicKey }; this._emitter.emit("login", this.user); return this.user; }); } logout() { this.user = null; this._emitter.emit("logout", void 0); return Promise.resolve(); } signMessage(data) { return this._ensureApi().then( (api) => api.signCustomData({ version: 1, binary: `base64:${btoa(String(data))}` }) ).then((result) => result.signature); } signTypedData(data) { return this._ensureApi().then( (api) => api.signCustomData({ version: 2, data }) ).then((result) => result.signature); } async sign(toSign) { const apiPromise = this._ensureApi(); if (toSign.length === 1) { return apiPromise.then((api) => api.signTransaction(keeperTxFactory(toSign[0]))).then((data) => [signerTxFactory(data)]); } return apiPromise.then( (api) => api.signTransactionPackage( toSign.map( (tx) => keeperTxFactory(tx) ) ) ).then((data) => data.map((tx) => signerTxFactory(tx))); } async _ensureApi() { const [api] = await Promise.all([this._apiPromise, this._connectPromise]); const state = await api.publicState(); const keeperNetworkByte = state.network.code.charCodeAt(0); const signerNetworkByte = this._options.NETWORK_BYTE; if (keeperNetworkByte !== signerNetworkByte) { const keeperNodeUrl = state.network.server; const signerNodeUrl = this._options.NODE_URL; throw new Error( `Invalid connect options. Signer connect (${signerNodeUrl} ${signerNetworkByte}) not equals keeper connect (${keeperNodeUrl} ${keeperNetworkByte})` ); } return api; } } const poll = (resolve, reject, attempt = 0, retries = 30, interval = 100) => { if (attempt > retries) return resolve(false); if (typeof WavesKeeper !== "undefined") { return resolve(true); } else setTimeout(() => poll(resolve, reject, ++attempt), interval); }; const _isKeeperInstalled = new Promise(poll); async function isKeeperInstalled() { return _isKeeperInstalled; } export { ProviderKeeper, isKeeperInstalled }; //# sourceMappingURL=index.js.map