text: "use strict";
  /**
   * @module API
   */
  // copyright defined in plasmajs/LICENSE.txt
  var __assign = (this && this.__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;
  };
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
      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) : new P(function (resolve) { resolve(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 __rest = (this && this.__rest) || function (s, e) {
      var t = {};
      for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
          t[p] = s[p];
      if (s != null && typeof Object.getOwnPropertySymbols === "function")
          for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0)
              t[p[i]] = s[p[i]];
      return t;
  };
  var __read = (this && this.__read) || function (o, n) {
      var m = typeof Symbol === "function" && o[Symbol.iterator];
      if (!m) return o;
      var i = m.call(o), r, ar = [], e;
      try {
          while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
      }
      catch (error) { e = { error: error }; }
      finally {
          try {
              if (r && !r.done && (m = i["return"])) m.call(i);
          }
          finally { if (e) throw e.error; }
      }
      return ar;
  };
  var __spread = (this && this.__spread) || function () {
      for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i]));
      return ar;
  };
  var __values = (this && this.__values) || function (o) {
      var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0;
      if (m) return m.call(o);
      return {
          next: function () {
              if (o && i >= o.length) o = void 0;
              return { value: o && o[i++], done: !o };
          }
      };
  };
  Object.defineProperty(exports, "__esModule", { value: true });
  var ser = require("./plasmajs-serialize");
  // tslint:disable-next-line
  var abiAbi = require('../src/abi.abi.json');
  // tslint:disable-next-line
  var transactionAbi = require('../src/transaction.abi.json');
  var Api = /** @class */ (function () {
      /**
       * @param args
       *    * `rpc`: Issues RPC calls
       *    * `authorityProvider`: Get public keys needed to meet authorities in a transaction
       *    * `abiProvider`: Supplies ABIs in raw form (binary)
       *    * `signatureProvider`: Signs transactions
       *    * `chainId`: Identifies chain
       *    * `textEncoder`: `TextEncoder` instance to use. Pass in `null` if running in a browser
       *    * `textDecoder`: `TextDecoder` instance to use. Pass in `null` if running in a browser
       */
      function Api(args) {
          /** Holds information needed to serialize contract actions */
          this.contracts = new Map();
          /** Fetched abis */
          this.cachedAbis = new Map();
          this.rpc = args.rpc;
          this.authorityProvider = args.authorityProvider || args.rpc;
          this.abiProvider = args.abiProvider || args.rpc;
          this.signatureProvider = args.signatureProvider;
          this.chainId = args.chainId;
          this.textEncoder = args.textEncoder;
          this.textDecoder = args.textDecoder;
          this.abiTypes = ser.getTypesFromAbi(ser.createInitialTypes(), abiAbi);
          this.transactionTypes = ser.getTypesFromAbi(ser.createInitialTypes(), transactionAbi);
      }
      /** Decodes an abi as Uint8Array into json. */
      Api.prototype.rawAbiToJson = function (rawAbi) {
          var buffer = new ser.SerialBuffer({
              textEncoder: this.textEncoder,
              textDecoder: this.textDecoder,
              array: rawAbi,
          });
          if (!ser.supportedAbiVersion(buffer.getString())) {
              throw new Error("Unsupported abi version");
          }
          buffer.restartRead();
          return this.abiTypes.get("abi_def").deserialize(buffer);
      };
      /** Get abi in both binary and structured forms. Fetch when needed. */
      Api.prototype.getCachedAbi = function (accountName, reload) {
          if (reload === void 0) { reload = false; }
          return __awaiter(this, void 0, void 0, function () {
              var cachedAbi, rawAbi, abi, e_1;
              return __generator(this, function (_a) {
                  switch (_a.label) {
                      case 0:
                          if (!reload && this.cachedAbis.get(accountName)) {
                              return [2 /*return*/, this.cachedAbis.get(accountName)];
                          }
                          _a.label = 1;
                      case 1:
                          _a.trys.push([1, 3, , 4]);
                          return [4 /*yield*/, this.abiProvider.getRawAbi(accountName)];
                      case 2:
                          rawAbi = (_a.sent()).abi;
                          abi = this.rawAbiToJson(rawAbi);
                          cachedAbi = { rawAbi: rawAbi, abi: abi };
                          return [3 /*break*/, 4];
                      case 3:
                          e_1 = _a.sent();
                          e_1.message = "fetching abi for " + accountName + ": " + e_1.message;
                          throw e_1;
                      case 4:
                          if (!cachedAbi) {
                              throw new Error("Missing abi for " + accountName);
                          }
                          this.cachedAbis.set(accountName, cachedAbi);
                          return [2 /*return*/, cachedAbi];
                  }
              });
          });
      };
      /** Get abi in structured form. Fetch when needed. */
      Api.prototype.getAbi = function (accountName, reload) {
          if (reload === void 0) { reload = false; }
          return __awaiter(this, void 0, void 0, function () {
              return __generator(this, function (_a) {
                  switch (_a.label) {
                      case 0: return [4 /*yield*/, this.getCachedAbi(accountName, reload)];
                      case 1: return [2 /*return*/, (_a.sent()).abi];
                  }
              });
          });
      };
      /** Get abis needed by a transaction */
      Api.prototype.getTransactionAbis = function (transaction, reload) {
          if (reload === void 0) { reload = false; }
          return __awaiter(this, void 0, void 0, function () {
              var accounts, uniqueAccounts, actionPromises;
              var _this = this;
              return __generator(this, function (_a) {
                  accounts = transaction.actions.map(function (action) { return action.account; });
                  uniqueAccounts = new Set(accounts);
                  actionPromises = __spread(uniqueAccounts).map(function (account) { return __awaiter(_this, void 0, void 0, function () {
                      var _a;
                      return __generator(this, function (_b) {
                          switch (_b.label) {
                              case 0:
                                  _a = {
                                      accountName: account
                                  };
                                  return [4 /*yield*/, this.getCachedAbi(account, reload)];
                              case 1: return [2 /*return*/, (_a.abi = (_b.sent()).rawAbi,
                                      _a)];
                          }
                      });
                  }); });
                  return [2 /*return*/, Promise.all(actionPromises)];
              });
          });
      };
      /** Get data needed to serialize actions in a contract */
      Api.prototype.getContract = function (accountName, reload) {
          if (reload === void 0) { reload = false; }
          return __awaiter(this, void 0, void 0, function () {
              var e_2, _a, abi, types, actions, _b, _c, _d, name_1, type, result;
              return __generator(this, function (_e) {
                  switch (_e.label) {
                      case 0:
                          if (!reload && this.contracts.get(accountName)) {
                              return [2 /*return*/, this.contracts.get(accountName)];
                          }
                          return [4 /*yield*/, this.getAbi(accountName, reload)];
                      case 1:
                          abi = _e.sent();
                          types = ser.getTypesFromAbi(ser.createInitialTypes(), abi);
                          actions = new Map();
                          try {
                              for (_b = __values(abi.actions), _c = _b.next(); !_c.done; _c = _b.next()) {
                                  _d = _c.value, name_1 = _d.name, type = _d.type;
                                  actions.set(name_1, ser.getType(types, type));
                              }
                          }
                          catch (e_2_1) { e_2 = { error: e_2_1 }; }
                          finally {
                              try {
                                  if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
                              }
                              finally { if (e_2) throw e_2.error; }
                          }
                          result = { types: types, actions: actions };
                          this.contracts.set(accountName, result);
                          return [2 /*return*/, result];
                  }
              });
          });
      };
      /** Convert `value` to binary form. `type` must be a built-in abi type or in `transaction.abi.json`. */
      Api.prototype.serialize = function (buffer, type, value) {
          this.transactionTypes.get(type).serialize(buffer, value);
      };
      /** Convert data in `buffer` to structured form. `type` must be a built-in abi type or in `transaction.abi.json`. */
      Api.prototype.deserialize = function (buffer, type) {
          return this.transactionTypes.get(type).deserialize(buffer);
      };
      /** Convert a transaction to binary */
      Api.prototype.serializeTransaction = function (transaction) {
          var buffer = new ser.SerialBuffer({ textEncoder: this.textEncoder, textDecoder: this.textDecoder });
          this.serialize(buffer, "transaction", __assign({ max_net_usage_words: 0, max_cpu_usage_ms: 0, delay_sec: 0, context_free_actions: [], actions: [], transaction_extensions: [] }, transaction));
          return buffer.asUint8Array();
      };
      /** Convert a transaction from binary. Leaves actions in hex. */
      Api.prototype.deserializeTransaction = function (transaction) {
          var buffer = new ser.SerialBuffer({ textEncoder: this.textEncoder, textDecoder: this.textDecoder });
          buffer.pushArray(transaction);
          return this.deserialize(buffer, "transaction");
      };
      /** Convert actions to hex */
      Api.prototype.serializeActions = function (actions) {
          return __awaiter(this, void 0, void 0, function () {
              var _this = this;
              return __generator(this, function (_a) {
                  switch (_a.label) {
                      case 0: return [4 /*yield*/, Promise.all(actions.map(function (_a) {
                              var account = _a.account, name = _a.name, authorization = _a.authorization, data = _a.data;
                              return __awaiter(_this, void 0, void 0, function () {
                                  var contract;
                                  return __generator(this, function (_b) {
                                      switch (_b.label) {
                                          case 0: return [4 /*yield*/, this.getContract(account)];
                                          case 1:
                                              contract = _b.sent();
                                              return [2 /*return*/, ser.serializeAction(contract, account, name, authorization, data, this.textEncoder, this.textDecoder)];
                                      }
                                  });
                              });
                          }))];
                      case 1: return [2 /*return*/, _a.sent()];
                  }
              });
          });
      };
      /** Convert actions from hex */
      Api.prototype.deserializeActions = function (actions) {
          return __awaiter(this, void 0, void 0, function () {
              var _this = this;
              return __generator(this, function (_a) {
                  switch (_a.label) {
                      case 0: return [4 /*yield*/, Promise.all(actions.map(function (_a) {
                              var account = _a.account, name = _a.name, authorization = _a.authorization, data = _a.data;
                              return __awaiter(_this, void 0, void 0, function () {
                                  var contract;
                                  return __generator(this, function (_b) {
                                      switch (_b.label) {
                                          case 0: return [4 /*yield*/, this.getContract(account)];
                                          case 1:
                                              contract = _b.sent();
                                              return [2 /*return*/, ser.deserializeAction(contract, account, name, authorization, data, this.textEncoder, this.textDecoder)];
                                      }
                                  });
                              });
                          }))];
                      case 1: return [2 /*return*/, _a.sent()];
                  }
              });
          });
      };
      /** Convert a transaction from binary. Also deserializes actions. */
      Api.prototype.deserializeTransactionWithActions = function (transaction) {
          return __awaiter(this, void 0, void 0, function () {
              var deserializedTransaction, deserializedActions;
              return __generator(this, function (_a) {
                  switch (_a.label) {
                      case 0:
                          if (typeof transaction === "string") {
                              transaction = ser.hexToUint8Array(transaction);
                          }
                          deserializedTransaction = this.deserializeTransaction(transaction);
                          return [4 /*yield*/, this.deserializeActions(deserializedTransaction.actions)];
                      case 1:
                          deserializedActions = _a.sent();
                          return [2 /*return*/, __assign({}, deserializedTransaction, { actions: deserializedActions })];
                  }
              });
          });
      };
      /**
       * Create and optionally broadcast a transaction.
       *
       * Named Parameters:
       *    * `broadcast`: broadcast this transaction?
       *    * `sign`: sign this transaction?
       *    * If both `blocksBehind` and `expireSeconds` are present,
       *      then fetch the block which is `blocksBehind` behind head block,
       *      use it as a reference for TAPoS, and expire the transaction `expireSeconds` after that block's time.
       * @returns node response if `broadcast`, `{signatures, serializedTransaction}` if `!broadcast`
       */
      Api.prototype.transact = function (transaction, _a) {
          var _b = _a === void 0 ? {} : _a, _c = _b.broadcast, broadcast = _c === void 0 ? true : _c, _d = _b.sign, sign = _d === void 0 ? true : _d, blocksBehind = _b.blocksBehind, expireSeconds = _b.expireSeconds;
          return __awaiter(this, void 0, void 0, function () {
              var info, refBlock, abis, _e, _f, serializedTransaction, pushTransactionArgs, availableKeys, requiredKeys;
              return __generator(this, function (_g) {
                  switch (_g.label) {
                      case 0:
                          if (!!this.chainId) return [3 /*break*/, 2];
                          return [4 /*yield*/, this.rpc.get_info()];
                      case 1:
                          info = _g.sent();
                          this.chainId = info.chain_id;
                          _g.label = 2;
                      case 2:
                          if (!(typeof blocksBehind === "number" && expireSeconds)) return [3 /*break*/, 6];
                          if (!!info) return [3 /*break*/, 4];
                          return [4 /*yield*/, this.rpc.get_info()];
                      case 3:
                          info = _g.sent();
                          _g.label = 4;
                      case 4: return [4 /*yield*/, this.rpc.get_block(info.head_block_num - blocksBehind)];
                      case 5:
                          refBlock = _g.sent();
                          transaction = __assign({}, ser.transactionHeader(refBlock, expireSeconds), transaction);
                          _g.label = 6;
                      case 6:
                          if (!this.hasRequiredTaposFields(transaction)) {
                              throw new Error("Required configuration or TAPOS fields are not present");
                          }
                          return [4 /*yield*/, this.getTransactionAbis(transaction)];
                      case 7:
                          abis = _g.sent();
                          _e = [{}, transaction];
                          _f = {};
                          return [4 /*yield*/, this.serializeActions(transaction.actions)];
                      case 8:
                          transaction = __assign.apply(void 0, _e.concat([(_f.actions = _g.sent(), _f)]));
                          serializedTransaction = this.serializeTransaction(transaction);
                          pushTransactionArgs = { serializedTransaction: serializedTransaction, signatures: [] };
                          if (!sign) return [3 /*break*/, 12];
                          return [4 /*yield*/, this.signatureProvider.getAvailableKeys()];
                      case 9:
                          availableKeys = _g.sent();
                          return [4 /*yield*/, this.authorityProvider.getRequiredKeys({ transaction: transaction, availableKeys: availableKeys })];
                      case 10:
                          requiredKeys = _g.sent();
                          return [4 /*yield*/, this.signatureProvider.sign({
                                  chainId: this.chainId,
                                  requiredKeys: requiredKeys,
                                  serializedTransaction: serializedTransaction,
                                  abis: abis,
                              })];
                      case 11:
                          pushTransactionArgs = _g.sent();
                          _g.label = 12;
                      case 12:
                          if (broadcast) {
                              return [2 /*return*/, this.pushSignedTransaction(pushTransactionArgs)];
                          }
                          return [2 /*return*/, pushTransactionArgs];
                  }
              });
          });
      };
      /** Broadcast a signed transaction */
      Api.prototype.pushSignedTransaction = function (_a) {
          var signatures = _a.signatures, serializedTransaction = _a.serializedTransaction;
          return __awaiter(this, void 0, void 0, function () {
              return __generator(this, function (_b) {
                  return [2 /*return*/, this.rpc.push_transaction({
                          signatures: signatures,
                          serializedTransaction: serializedTransaction,
                      })];
              });
          });
      };
      // eventually break out into TransactionValidator class
      Api.prototype.hasRequiredTaposFields = function (_a) {
          var expiration = _a.expiration, ref_block_num = _a.ref_block_num, ref_block_prefix = _a.ref_block_prefix, transaction = __rest(_a, ["expiration", "ref_block_num", "ref_block_prefix"]);
          return !!(expiration && ref_block_num && ref_block_prefix);
      };
      return Api;
  }()); // Api
  exports.default = Api;
  //# sourceMappingURL=plasmajs-api.js.map