@waves/provider-keeper
Version:
ProviderKeeper for Signer
315 lines (314 loc) • 9.36 kB
JavaScript
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