@logosnetwork/logos-webwallet-sdk
Version:
Create Logos wallets with or without a full Logos node
1,031 lines (1,030 loc) • 90.2 kB
JavaScript
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
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 __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var Utils_1 = require("./Utils/Utils");
var big_integer_1 = __importDefault(require("big-integer"));
var Account_1 = __importDefault(require("./Account"));
var Requests_1 = require("./Requests");
/**
* ## Logos Account
* This class is the base class of an account on the Logos Network.
* The most common uses for this account is to check the balance, history, and create new requests from this account as the origin.
*/
var LogosAccount = /** @class */ (function (_super) {
__extends(LogosAccount, _super);
/**
* ### Instantiating
* ```typescript
* const LogosAccount = new LogosAccount({
* label: null,
* address: null,
* publicKey: null,
* balance: '0',
* pendingBalance: '0',
* wallet: null,
* chain: [],
* receiveChain: [],
* pendingChain: [],
* privateKey: null
* tokenBalances: {},
* tokens: [],
* pendingTokenBalances: {},
* index: null
* })
* ```
*
* All logos account options are optional defaults are shown in the example above
*
* |Account Options| Description |
* |--|--|
* | label | Account label e.g. Checking Account |
* | address | Address is the lgs_ string |
* | publicKey | Public key of the account |
* | balance | Balance of the account in the minor unit of Logos |
* | pendingBalance | balance of the account including pending transaction in the minor unit of Logos |
* | wallet | reference back to the parent wallet class |
* | chain | Array of [[Request]] that are confirmed on this account's send chain |
* | receiveChain | Array of [[Request]] that are confirmed on this account's receive chain |
* | pendingChain | Array of [[Request]] that are *not* confirmed on this account's send chain |
* | [[privateKey]] | Private key of the account used to sign transactions |
* | [[tokenBalances]] | Balances tokens that this account has in their |
* | [[tokens]] | Array of token addresses associated with this account |
* | [[pendingTokenBalances]] | Unconfirmed balances of the tokens |
* | [[index]] | index of the account |
*/
function LogosAccount(options) {
if (options === void 0) { options = {
privateKey: null,
tokenBalances: {},
tokens: [],
pendingTokenBalances: {},
index: null
}; }
var _this = _super.call(this, options) || this;
/**
* Deterministic Key Index used to generate this account - null means generated explicitly
*
* @type {number}
* @private
*/
if (options.index !== undefined) {
_this._index = options.index;
}
else {
_this._index = null;
}
/**
* Private Key of this account
* @type {string}
* @private
*/
if (options.privateKey !== undefined) {
_this._privateKey = options.privateKey;
}
else {
_this._privateKey = null;
}
/**
* Tokens that are associated with your account
* @type {string[]}
* @private
*/
if (options.tokens !== undefined) {
_this._tokens = options.tokens;
}
else {
_this._tokens = [];
}
/**
* Token Balance of the token account in minor unit of tokens
* @type {TokenBalances}
* @private
*/
if (options.tokenBalances !== undefined) {
_this._tokenBalances = options.tokenBalances;
}
else {
_this._tokenBalances = {};
}
/**
* Pending Token Balance of the token account in minor unit of tokens
*
* pending token balance is the token balance minus the token sends that are pending
* @type {TokenBalances}
* @private
*/
if (options.pendingTokenBalances !== undefined) {
_this._pendingTokenBalances = options.pendingTokenBalances;
}
else {
_this._pendingTokenBalances = {};
}
return _this;
}
Object.defineProperty(LogosAccount.prototype, "type", {
/**
* The type of the account (LogosAccount or TokenAccount)
* #### Example
* ```typescript
* const type = logosAccount.type
* ```
*/
get: function () {
return 'LogosAccount';
},
enumerable: true,
configurable: true
});
Object.defineProperty(LogosAccount.prototype, "index", {
/**
* The index of the account
* #### Example
* ```typescript
* const index = logosAccount.index
* ```
*/
get: function () {
return this._index;
},
enumerable: true,
configurable: true
});
Object.defineProperty(LogosAccount.prototype, "privateKey", {
/**
* The private key of the account
* #### Example
* ```typescript
* const privateKey = logosAccount.privateKey
* ```
*/
get: function () {
return this._privateKey;
},
enumerable: true,
configurable: true
});
Object.defineProperty(LogosAccount.prototype, "tokens", {
/**
* Array of associated token ids to this account (full list available only with fullsync)
* #### Example
* ```typescript
* const tokens = logosAccount.tokens
* ```
*/
get: function () {
return this._tokens;
},
enumerable: true,
configurable: true
});
Object.defineProperty(LogosAccount.prototype, "tokenBalances", {
/**
* The balance of the tokens in the minor token unit
* #### Example
* ```typescript
* const tokenBalances = logosAccount.tokenBalances
* ```
*/
get: function () {
return this._tokenBalances;
},
enumerable: true,
configurable: true
});
Object.defineProperty(LogosAccount.prototype, "pendingTokenBalances", {
/**
* The pending token balance of the account in the minor token unit
*
* pending token balance is balance minus the token sends that are pending
*
* #### Example
* ```typescript
* const pendingTokenBalances = logosAccount.pendingTokenBalances
* ```
*/
get: function () {
return this._pendingTokenBalances;
},
enumerable: true,
configurable: true
});
/**
* The balance of the given token in the minor unit and major unit (if available)
* @param {string} tokenID - Token ID of the token in question, you can also send the token account address
* @returns {{minor: string;major?: string}} The balance in minor unit or converted units
* #### Example
* ```typescript
* const tokenBalance = logosAccount.tokenBalance('lgs_3q69z3kf6cq9n9smago3p1ptuyqy9pa3mdykyi9o8f7gnof47qdyxj9gejxd')
* ```
*/
LogosAccount.prototype.tokenBalance = function (token) {
var tokenAccountKey = Utils_1.keyFromAccount(token);
var tokenAddress = Utils_1.accountFromHexKey(tokenAccountKey);
var minorValue = this.tokenBalances[tokenAccountKey];
if (minorValue) {
var result = {
minor: minorValue
};
if (!this.wallet.tokenAccounts[tokenAddress])
return result;
result.major = this.wallet.tokenAccounts[tokenAddress].convertToMajor(minorValue);
return result;
}
else {
return null;
}
};
/**
* Adds a token to the accounts associated tokens if it doesn't already exist
*
* @param {string} tokenID - The TokenID you are associating with this account (this will be converted into a token account when stored)
* @returns {string[]} Array of all the associated tokens
* #### Example
* ```typescript
* const token = await logosAccount.addToken('lgs_3q69z3kf6cq9n9smago3p1ptuyqy9pa3mdykyi9o8f7gnof47qdyxj9gejxd')
* ```
*/
LogosAccount.prototype.addToken = function (tokenID) {
return __awaiter(this, void 0, void 0, function () {
var tokenAddress;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
tokenAddress = Utils_1.accountFromHexKey(tokenID);
if (!!this.tokens.includes(tokenAddress)) return [3 /*break*/, 2];
this.tokens.push(tokenAddress);
if (!this.wallet.tokenSync) return [3 /*break*/, 2];
return [4 /*yield*/, this.wallet.createTokenAccount(tokenAddress)];
case 1:
_a.sent();
_a.label = 2;
case 2: return [2 /*return*/, this.tokens];
}
});
});
};
/**
* Checks if the account is synced
* @returns {Promise<SyncedResponse>}
* #### Example
* ```typescript
* const isSynced = await logosAccount.isSynced()
* ```
*/
LogosAccount.prototype.isSynced = function () {
var _this = this;
return new Promise(function (resolve) {
var RPC = _this.wallet.rpcClient;
RPC.accounts.info(_this.address).then(function (info) { return __awaiter(_this, void 0, void 0, function () {
var synced, receiveBlock;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
synced = true;
if (!(info && info.frontier)) return [3 /*break*/, 3];
if (info.frontier !== Utils_1.GENESIS_HASH) {
if (this.chain.length === 0 || this.chain[this.chain.length - 1].hash !== info.frontier) {
synced = false;
}
}
if (!synced) return [3 /*break*/, 2];
return [4 /*yield*/, RPC.requests.info(info.receive_tip)];
case 1:
receiveBlock = _a.sent();
if (this.receiveChain.length === 0 || this.receiveChain[this.receiveChain.length - 1].hash !== receiveBlock.send_hash) {
synced = false;
}
_a.label = 2;
case 2:
if (synced) {
this.updateBalancesFromChain();
if (this.wallet.validateSync) {
if (this.verifyChain() && this.verifyReceiveChain()) {
this.synced = synced;
console.info(this.address + " has been fully synced and validated");
resolve({ account: this.address, synced: this.synced, type: 'LogosAccount' });
}
}
else {
console.info('Finished Syncing: Requests were not validated');
this.synced = synced;
resolve({ account: this.address, synced: this.synced, type: 'LogosAccount' });
}
}
else {
this.synced = synced;
resolve({ account: this.address, synced: this.synced, type: 'LogosAccount' });
}
return [3 /*break*/, 4];
case 3:
if (this.receiveChain.length === 0 && this.chain.length === 0) {
console.info(this.address + " is empty and therefore valid");
this.synced = synced;
resolve({ account: this.address, synced: this.synced, type: 'LogosAccount' });
}
else {
console.error(this.address + " is not opened according to the RPC. This is a critical error if in a production enviroment. On testnet this just means the network has been restarted.");
this.synced = false;
resolve({ account: this.address, synced: this.synced, type: 'LogosAccount' });
}
_a.label = 4;
case 4: return [2 /*return*/];
}
});
}); });
});
};
/**
* Scans the account history using RPC and updates the local chain
*
* @returns {Promise<Account>}
* #### Example
* ```typescript
* const isSynced = await logosAccount.sync()
* ```
*/
LogosAccount.prototype.sync = function () {
var _this = this;
return new Promise(function (resolve) {
_this.synced = false;
_this.chain = [];
_this.receiveChain = [];
_this.pendingChain = [];
_this._tokenBalances = {};
_this.balance = '0';
_this.pendingBalance = '0';
_this._tokens = [];
_this._pendingTokenBalances = {};
var RPC = _this.wallet.rpcClient;
if (_this.wallet.fullSync) {
RPC.accounts.history(_this.address, -1, true).then(function (history) { return __awaiter(_this, void 0, void 0, function () {
var _i, _a, requestInfo;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
if (!history) return [3 /*break*/, 5];
_i = 0, _a = history.reverse();
_b.label = 1;
case 1:
if (!(_i < _a.length)) return [3 /*break*/, 4];
requestInfo = _a[_i];
return [4 /*yield*/, this.addConfirmedRequest(requestInfo)];
case 2:
_b.sent();
_b.label = 3;
case 3:
_i++;
return [3 /*break*/, 1];
case 4:
this.updateBalancesFromChain();
if (this.wallet.validateSync) {
if (this.verifyChain() && this.verifyReceiveChain()) {
this.synced = true;
console.info(this.address + " has been fully synced and validated");
resolve(this);
}
}
else {
console.info('Finished Syncing: Requests were not validated');
this.synced = true;
resolve(this);
}
return [3 /*break*/, 6];
case 5:
this.synced = true;
console.info(this.address + " is empty and therefore valid");
resolve(this);
_b.label = 6;
case 6: return [2 /*return*/];
}
});
}); });
}
else {
RPC.accounts.info(_this.address).then(function (info) {
if (info && info.frontier && info.frontier !== Utils_1.GENESIS_HASH) {
RPC.requests.info(info.frontier).then(function (val) { return __awaiter(_this, void 0, void 0, function () {
var request, tokenBalances, _i, _a, _b, tokenID, accountInfo;
return __generator(this, function (_c) {
switch (_c.label) {
case 0: return [4 /*yield*/, this.addConfirmedRequest(val)];
case 1:
request = _c.sent();
if (request !== null && !request.verify()) {
throw new Error("Invalid Request from RPC sync! \n " + JSON.stringify(request.toJSON(), null, 2));
}
if (info.balance) {
this.balance = info.balance;
this.pendingBalance = info.balance;
}
tokenBalances = {};
if (info.tokens) {
for (_i = 0, _a = Object.entries(info.tokens); _i < _a.length; _i++) {
_b = _a[_i], tokenID = _b[0], accountInfo = _b[1];
this.addToken(tokenID);
tokenBalances[tokenID] = accountInfo.balance;
}
this._tokenBalances = __assign({}, tokenBalances);
this._pendingTokenBalances = __assign({}, tokenBalances);
}
this.synced = true;
console.info(this.address + " has been lazy synced");
resolve(this);
return [2 /*return*/];
}
});
}); });
}
else {
if (info) {
if (info.balance) {
_this.balance = info.balance;
_this.pendingBalance = info.balance;
}
var tokenBalances = {};
if (info.tokens) {
for (var _i = 0, _a = Object.entries(info.tokens); _i < _a.length; _i++) {
var _b = _a[_i], tokenID = _b[0], accountInfo = _b[1];
_this.addToken(tokenID);
tokenBalances[tokenID] = accountInfo.balance;
}
_this._tokenBalances = __assign({}, tokenBalances);
_this._pendingTokenBalances = __assign({}, tokenBalances);
}
}
_this.synced = true;
console.info(_this.address + " is empty and therefore valid");
resolve(_this);
}
});
}
});
};
/**
* Updates the balances of the account by traversing the chain
* @returns {void}
* #### Example
* ```typescript
* logosAccount.updateBalancesFromChain()
* ```
*/
LogosAccount.prototype.updateBalancesFromChain = function () {
var sum = big_integer_1.default(0);
var tokenSums = {};
for (var _i = 0, _a = this.receiveChain; _i < _a.length; _i++) {
var request = _a[_i];
if (request instanceof Requests_1.Send) {
for (var _b = 0, _c = request.transactions; _b < _c.length; _b++) {
var transaction = _c[_b];
if (transaction.destination === this.address) {
sum = sum.plus(big_integer_1.default(transaction.amount));
}
}
}
else if (request instanceof Requests_1.WithdrawLogos) {
if (request.transaction.destination === this.address) {
sum = sum.plus(big_integer_1.default(request.transaction.amount));
}
}
else if (request instanceof Requests_1.TokenSend) {
for (var _d = 0, _e = request.transactions; _d < _e.length; _d++) {
var transaction = _e[_d];
if (transaction.destination === this.address) {
tokenSums[request.tokenID] = big_integer_1.default(tokenSums[request.tokenID]).plus(big_integer_1.default(transaction.amount)).toString();
}
}
}
else if (request instanceof Requests_1.Distribute || request instanceof Requests_1.WithdrawFee || request instanceof Requests_1.Revoke) {
if (request.transaction.destination === this.address) {
tokenSums[request.tokenID] = big_integer_1.default(tokenSums[request.tokenID]).plus(big_integer_1.default(request.transaction.amount)).toString();
}
if (request instanceof Requests_1.Revoke && request.source === this.address) {
tokenSums[request.tokenID] = big_integer_1.default(tokenSums[request.tokenID]).minus(big_integer_1.default(request.transaction.amount)).toString();
}
}
}
for (var _f = 0, _g = this.chain; _f < _g.length; _f++) {
var request = _g[_f];
if (request instanceof Requests_1.Send) {
sum = sum.minus(big_integer_1.default(request.totalAmount)).minus(big_integer_1.default(request.fee));
}
else if (request instanceof Requests_1.TokenSend) {
tokenSums[request.tokenID] = big_integer_1.default(tokenSums[request.tokenID]).minus(big_integer_1.default(request.totalAmount)).minus(big_integer_1.default(request.tokenFee)).toString();
sum = sum.minus(big_integer_1.default(request.fee));
}
else if (request instanceof Requests_1.Issuance) {
sum = sum.minus(big_integer_1.default(request.fee));
}
}
this.balance = sum.toString();
this._tokenBalances = __assign({}, tokenSums);
for (var _h = 0, _j = this.pendingChain; _h < _j.length; _h++) {
var pendingRequest = _j[_h];
if (pendingRequest instanceof Requests_1.Send) {
sum = sum.minus(big_integer_1.default(pendingRequest.totalAmount)).minus(big_integer_1.default(pendingRequest.fee));
for (var _k = 0, _l = pendingRequest.transactions; _k < _l.length; _k++) {
var transaction = _l[_k];
if (transaction.destination === this.address) {
sum = sum.plus(big_integer_1.default(transaction.amount));
}
}
}
else if (pendingRequest instanceof Requests_1.TokenSend) {
sum = sum.minus(big_integer_1.default(pendingRequest.fee));
tokenSums[pendingRequest.tokenID] = big_integer_1.default(tokenSums[pendingRequest.tokenID]).minus(big_integer_1.default(pendingRequest.totalAmount)).minus(big_integer_1.default(pendingRequest.tokenFee)).toString();
for (var _m = 0, _o = pendingRequest.transactions; _m < _o.length; _m++) {
var transaction = _o[_m];
if (transaction.destination === this.address) {
tokenSums[pendingRequest.tokenID] = big_integer_1.default(tokenSums[pendingRequest.tokenID]).plus(big_integer_1.default(transaction.amount)).toString();
}
}
}
else if (pendingRequest.type === 'issuance') {
sum = sum.minus(big_integer_1.default(pendingRequest.fee));
}
}
this.pendingBalance = sum.toString();
this._pendingTokenBalances = __assign({}, tokenSums);
};
/**
* Updates the balances of the account by doing math on the previous balance when given a new request
* Also updates the pending balance based on the new balance and the pending chain
* @param {Request} request - request that is being calculated on
* #### Example
* ```typescript
* logosAccount.updateBalancesFromRequest()
* ```
*/
LogosAccount.prototype.updateBalancesFromRequest = function (request) {
var sum = big_integer_1.default(this.balance);
var tokenSums = this.tokenBalances;
if (request instanceof Requests_1.Send) {
if (request.originAccount === this.address) {
sum = sum.minus(big_integer_1.default(request.totalAmount)).minus(big_integer_1.default(request.fee));
}
for (var _i = 0, _a = request.transactions; _i < _a.length; _i++) {
var transaction = _a[_i];
if (transaction.destination === this.address) {
sum = sum.plus(big_integer_1.default(transaction.amount));
}
}
}
else if (request instanceof Requests_1.TokenSend) {
sum = sum.minus(big_integer_1.default(request.fee));
if (request.originAccount === this.address) {
tokenSums[request.tokenID] = big_integer_1.default(tokenSums[request.tokenID]).minus(big_integer_1.default(request.totalAmount)).minus(big_integer_1.default(request.tokenFee)).toString();
}
for (var _b = 0, _c = request.transactions; _b < _c.length; _b++) {
var transaction = _c[_b];
if (transaction.destination === this.address) {
tokenSums[request.tokenID] = big_integer_1.default(tokenSums[request.tokenID]).plus(big_integer_1.default(transaction.amount)).toString();
}
}
}
else if (request instanceof Requests_1.Issuance) {
sum = sum.minus(big_integer_1.default(request.fee));
}
else if (request instanceof Requests_1.WithdrawLogos) {
if (request.transaction.destination === this.address) {
sum = sum.plus(big_integer_1.default(request.transaction.amount));
}
}
else if (request instanceof Requests_1.Distribute || request instanceof Requests_1.WithdrawFee || request instanceof Requests_1.Revoke) {
if (request.transaction.destination === this.address) {
tokenSums[request.tokenID] = big_integer_1.default(tokenSums[request.tokenID]).plus(big_integer_1.default(request.transaction.amount)).toString();
}
if (request instanceof Requests_1.Revoke && request.source === this.address) {
tokenSums[request.tokenID] = big_integer_1.default(tokenSums[request.tokenID]).minus(big_integer_1.default(request.transaction.amount)).toString();
}
}
this.balance = sum.toString();
this._tokenBalances = __assign({}, tokenSums);
for (var _d = 0, _e = this.pendingChain; _d < _e.length; _d++) {
var pendingRequest = _e[_d];
if (pendingRequest instanceof Requests_1.Send) {
sum = sum.minus(big_integer_1.default(pendingRequest.totalAmount)).minus(big_integer_1.default(pendingRequest.fee));
for (var _f = 0, _g = pendingRequest.transactions; _f < _g.length; _f++) {
var transaction = _g[_f];
if (transaction.destination === this.address) {
sum = sum.plus(big_integer_1.default(transaction.amount));
}
}
}
else if (pendingRequest instanceof Requests_1.TokenSend) {
sum = sum.minus(big_integer_1.default(pendingRequest.fee));
tokenSums[pendingRequest.tokenID] = big_integer_1.default(tokenSums[pendingRequest.tokenID]).minus(big_integer_1.default(pendingRequest.totalAmount)).minus(big_integer_1.default(pendingRequest.tokenFee)).toString();
for (var _h = 0, _j = pendingRequest.transactions; _h < _j.length; _h++) {
var transaction = _j[_h];
if (transaction.destination === this.address) {
tokenSums[pendingRequest.tokenID] = big_integer_1.default(tokenSums[pendingRequest.tokenID]).plus(big_integer_1.default(transaction.amount)).toString();
}
}
}
else if (pendingRequest.type === 'issuance') {
sum = sum.minus(big_integer_1.default(pendingRequest.fee));
}
}
this.pendingBalance = sum.toString();
this._pendingTokenBalances = __assign({}, tokenSums);
};
/**
* Creates a request object from the mqtt info and adds the request to the appropriate chain
*
* @param {RequestOptions} requestInfo - Request information from the RPC or MQTT
* #### Example
* ```typescript
* logosAccount.addConfirmedRequest([[RpcRequest]])
* ```
*/
LogosAccount.prototype.addConfirmedRequest = function (requestInfo) {
return __awaiter(this, void 0, void 0, function () {
var request, _i, _a, trans;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
request = null;
if (!requestInfo.token_id) return [3 /*break*/, 2];
return [4 /*yield*/, this.addToken(requestInfo.token_id)];
case 1:
_b.sent();
_b.label = 2;
case 2:
if (requestInfo.type === 'send' || requestInfo.type === 'token_send') {
if (requestInfo.type === 'send') {
request = new Requests_1.Send(requestInfo);
}
else {
request = new Requests_1.TokenSend(requestInfo);
}
// If this request was created by us
// add the request to confirmed chain
if (request.originAccount === this.address) {
this.addToSendChain(request);
}
// If the request has transactions pointed to us
// add the request to the receive chain
if (request.transactions && request.transactions.length > 0) {
for (_i = 0, _a = request.transactions; _i < _a.length; _i++) {
trans = _a[_i];
if (trans.destination === this.address) {
this.addToReceiveChain(request);
break;
}
}
}
return [2 /*return*/, request];
}
else if (requestInfo.type === 'issuance') {
request = new Requests_1.Issuance(requestInfo);
this.addToSendChain(request);
return [2 /*return*/, request];
}
else if (requestInfo.type === 'distribute') {
request = new Requests_1.Distribute(requestInfo);
this.addToReceiveChain(request);
return [2 /*return*/, request];
}
else if (requestInfo.type === 'withdraw_fee') {
request = new Requests_1.WithdrawFee(requestInfo);
this.addToReceiveChain(request);
return [2 /*return*/, request];
}
else if (requestInfo.type === 'revoke') {
request = new Requests_1.Revoke(requestInfo);
this.addToReceiveChain(request);
return [2 /*return*/, request];
}
else if (requestInfo.type === 'withdraw_logos') {
request = new Requests_1.WithdrawLogos(requestInfo);
this.addToReceiveChain(request);
return [2 /*return*/, request];
}
else {
console.error("Error processing new request for logos account " + this.address + " unknown block type: " + requestInfo.type + " hash: " + requestInfo.hash);
return [2 /*return*/, null];
}
return [2 /*return*/];
}
});
});
};
/**
* Removes all pending requests from the pending chain
* #### Example
* ```typescript
* logosAccount.removePendingRequests()
* ```
*/
LogosAccount.prototype.removePendingRequests = function () {
_super.prototype.removePendingRequests.call(this);
this._pendingTokenBalances = __assign({}, this.tokenBalances);
};
/**
* Validates that the account has enough funds at the current time to publish the request
*
* @param {Request} request - Request Class
* #### Example
* ```typescript
* await logosAccount.validateRequest(REQUEST)
* ```
*/
LogosAccount.prototype.validateRequest = function (request) {
return __awaiter(this, void 0, void 0, function () {
var tokenAccount;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!(request instanceof Requests_1.Send)) return [3 /*break*/, 1];
if (big_integer_1.default(this.balance).minus(big_integer_1.default(request.totalAmount)).minus(request.fee).lesser(0)) {
console.error('Invalid Request: Not Enough Funds including fee to send that amount');
return [2 /*return*/, false];
}
return [2 /*return*/, true];
case 1:
if (!(request instanceof Requests_1.TokenSend)) return [3 /*break*/, 3];
return [4 /*yield*/, this.getTokenAccount(request.tokenID)];
case 2:
tokenAccount = _a.sent();
if (big_integer_1.default(this.balance).minus(request.fee).lesser(0)) {
console.error('Invalid Token Send Request: Not Enough Logos to pay the logos fee for token sends');
return [2 /*return*/, false];
}
if (!this.tokenBalances[tokenAccount.tokenID]) {
console.error('Invalid Token Send Request: User doesn\'t have a token account with the specified token');
return [2 /*return*/, false];
}
if (tokenAccount.feeType === 'flat' && big_integer_1.default(tokenAccount.feeRate).greater(request.tokenFee)) {
console.error("Invalid Token Send Request: Requests token is less than the required flat token fee of " + tokenAccount.feeRate);
return [2 /*return*/, false];
}
if (tokenAccount.feeType === 'percentage' &&
big_integer_1.default(request.totalAmount)
.multiply(big_integer_1.default(tokenAccount.feeRate))
.divide(100)
.greater(big_integer_1.default(request.tokenFee))) {
console.error("Invalid Token Send Request: Requests token is less than the required percentage token fee of " + tokenAccount.feeRate + "%");
return [2 /*return*/, false];
}
if (big_integer_1.default(this.tokenBalances[tokenAccount.tokenID]).minus(big_integer_1.default(request.totalAmount)).minus(big_integer_1.default(request.tokenFee)).lesser(0)) {
console.error('Invalid Token Send Request: Not Enough Token to pay the token fee for token sends');
return [2 /*return*/, false];
}
return [2 /*return*/, true];
case 3:
if (request.type === 'issuance') {
if (big_integer_1.default(this.balance).minus(request.fee).lesser(0)) {
console.error('Invalid Issuance Request: Account does not have enough Logos to afford the fee to broadcast an issuance');
return [2 /*return*/, false];
}
return [2 /*return*/, true];
}
_a.label = 4;
case 4: return [2 /*return*/, false];
}
});
});
};
/**
* Adds the request to the pending chain and publishes it
*
* @param {Request} request - Request information from the RPC or MQTT
* @throws An exception if the pending balance is less than the required amount to adjust a users status
* #### Example
* ```typescript
* const request = await logosAccount.addRequest(REQUEST)
* ```
*/
LogosAccount.prototype.addRequest = function (request) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
request.sign(this.privateKey);
return [2 /*return*/, _super.prototype.addRequest.call(this, request)];
});
});
};
/**
* Creates a request from the specified information
*
* @param {Transaction[]} transactions - The account destinations and amounts you wish to send them
* @throws An exception if the account has not been synced
* @throws An exception if the pending balance is less than the required amount to do a send
* @throws An exception if the request is rejected by the RPC
* #### Example
* ```typescript
* const request = await logosAccount.createSendRequest([
* {
* destination: 'lgs_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpiij4txtdo',
* amount: '1'
* }
* ])
* ```
*/
LogosAccount.prototype.createSendRequest = function (transactions) {
return __awaiter(this, void 0, void 0, function () {
var request, result;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (this.synced === false)
throw new Error('This account has not been synced or is being synced with the RPC network');
request = new Requests_1.Send({
signature: null,
previous: this.previous,
fee: Utils_1.minimumFee,
transactions: transactions,
sequence: this.sequence,
origin: this.address
});
if (!this.wallet.lazyErrors) {
if (big_integer_1.default(this.pendingBalance).minus(big_integer_1.default(request.totalAmount)).minus(request.fee).lesser(0)) {
throw new Error('Invalid Request: Not Enough Funds including fee to send that amount');
}
}
this.pendingBalance = big_integer_1.default(this.pendingBalance).minus(big_integer_1.default(request.totalAmount)).minus(request.fee).toString();
return [4 /*yield*/, this.addRequest(request)];
case 1:
result = _a.sent();
return [2 /*return*/, result];
}
});
});
};
/**
* Creates a request from the specified information
*
* @param {TokenIssuanceOptions} options - The options for the token creation
* @throws An exception if the account has not been synced
* @throws An exception if the pending balance is less than the required amount to do a token issuance
* @throws An exception if the request is rejected by the RPC
* #### Example
* ```typescript
* const request = await logosAccount.createTokenIssuanceRequest(
* {
* name: `UnitTestCoin`,
* symbol: `UTC`,
* totalSupply: '1000',
* feeRate: '1',
* issuerInfo: '{"decimals":0,"website":"https://github.com/LogosNetwork/logos-webwallet-sdk"}',
* settings: {
* issuance: true,
* modify_issuance: true,
* revoke: true,
* modify_revoke: true,
* freeze: true,
* modify_freeze: true,
* adjust_fee: true,
* modify_adjust_fee: true,
* whitelist: false,
* modify_whitelist: true
* },
* controllers: [{
* account: 'lgs_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpiij4txtdo',
* privileges: {
* change_issuance: true,
* change_modify_issuance: true,
* change_revoke: true,
* change_modify_revoke: true,
* change_freeze: true,
* change_modify_freeze: true,
* change_adjust_fee: true,
* change_modify_adjust_fee: true,
* change_whitelist: true,
* change_modify_whitelist: true,
* issuance: true,
* revoke: true,
* freeze: true,
* adjust_fee: true,
* whitelist: true,
* update_issuer_info: true,
* update_controller: true,
* burn: true,
* distribute: true,
* withdraw_fee: true,
* withdraw_logos: true
* }
* }]
* }
* )
* ```
*/
LogosAccount.prototype.createTokenIssuanceRequest = function (options) {
return __awaiter(this, void 0, void 0, function () {
var request, result;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!options.name)
throw new Error('You must pass name as a part of the TokenOptions');
if (!options.symbol)
throw new Error('You must pass symbol as a part of the TokenOptions');
if (this.synced === false)
throw new Error('This account has not been synced or is being synced with the RPC network');
request = new Requests_1.Issuance({
signature: null,
previous: this.previous,
fee: Utils_1.minimumFee,
sequence: this.sequence,
origin: this.address,
name: options.name,
symbol: options.symbol
});
if (options.feeType) {
request.feeType = options.feeType;
}
if (options.feeRate) {
request.feeRate = options.feeRate;
}
if (options.totalSupply) {
request.totalSupply = options.totalSupply;
}
if (options.settings) {
request.settings = options.settings;
}
if (options.controllers) {
request.controllers = options.controllers;
}
if (options.issuerInfo) {
request.issuerInfo = options.issuerInfo;
}
if (!this.wallet.lazyErrors) {
if (big_integer_1.default(this.pendingBalance).minus(request.fee).lesser(0)) {
throw new Error('Invalid Request: Not Enough Logos to afford the fee to issue a token');
}
}
this.pendingBalance = big_integer_1.default(this.pendingBalance).minus(request.fee).toString();
return [4 /*yield*/, this.wallet.createTokenAccount(Utils_1.accountFromHexKey(request.tokenID), request)];
case 1:
_a.sent();
return [4 /*yield*/, this.addRequest(request)];
case 2:
result = _a.sent();
return [2 /*return*/, result];
}
});
});
};
/**
* Gets tokenAccount
*