lib/server.js

  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.Server = exports.SUBMIT_TRANSACTION_TIMEOUT = exports.Durability = void 0;
  6. var _urijs = _interopRequireDefault(require("urijs"));
  7. var _stellarBase = require("stellar-base");
  8. var _axios = _interopRequireDefault(require("./axios"));
  9. var jsonrpc = _interopRequireWildcard(require("./jsonrpc"));
  10. var _soroban_rpc = require("./soroban_rpc");
  11. var _transaction = require("./transaction");
  12. var _parsers = require("./parsers");
  13. function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
  14. function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
  15. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  16. /* tslint:disable:variable-name no-namespace */
  17. const SUBMIT_TRANSACTION_TIMEOUT = exports.SUBMIT_TRANSACTION_TIMEOUT = 60 * 1000;
  18. /**
  19. * Specifies the durability namespace of contract-related ledger entries.
  20. */
  21. let Durability = exports.Durability = /*#__PURE__*/function (Durability) {
  22. Durability["Temporary"] = "temporary";
  23. Durability["Persistent"] = "persistent";
  24. return Durability;
  25. }({});
  26. /**
  27. * Handles the network connection to a Soroban RPC instance, exposing an
  28. * interface for requests to that instance.
  29. *
  30. * @constructor
  31. *
  32. * @param {string} serverURL Soroban-RPC Server URL (ex.
  33. * `http://localhost:8000/soroban/rpc`).
  34. * @param {object} [opts] Options object
  35. * @param {boolean} [opts.allowHttp] allows connecting to insecure http servers
  36. * (default: `false`). This must be set to false in production deployments!
  37. * You can also use {@link Config} class to set this globally.
  38. * @param {Record<string, string>} [opts.headers] allows setting custom headers
  39. *
  40. * @see https://soroban.stellar.org/api/methods
  41. */
  42. class Server {
  43. /** Soroban RPC Server URL (ex. `http://localhost:8000/soroban/rpc`). */
  44. constructor(serverURL, opts = {}) {
  45. this.serverURL = (0, _urijs.default)(serverURL);
  46. if (opts.headers && Object.keys(opts.headers).length === 0) {
  47. _axios.default.interceptors.request.use(config => {
  48. // merge the custom headers into any existing headers
  49. config.headers = Object.assign(config.headers, opts.headers);
  50. return config;
  51. });
  52. }
  53. if (this.serverURL.protocol() !== 'https' && !opts.allowHttp) {
  54. throw new Error("Cannot connect to insecure Soroban RPC server if `allowHttp` isn't set");
  55. }
  56. }
  57. /**
  58. * Fetch a minimal set of current info about a Stellar account.
  59. *
  60. * Needed to get the current sequence number for the account so you can build
  61. * a successful transaction with {@link TransactionBuilder}.
  62. *
  63. * @param {string} address - The public address of the account to load.
  64. *
  65. * @returns {Promise<Account>} a promise to the {@link Account} object with
  66. * a populated sequence number
  67. *
  68. * @see https://soroban.stellar.org/api/methods/getLedgerEntries
  69. * @example
  70. * const accountId = "GBZC6Y2Y7Q3ZQ2Y4QZJ2XZ3Z5YXZ6Z7Z2Y4QZJ2XZ3Z5YXZ6Z7Z2Y4";
  71. * server.getAccount(accountId).then((account) => {
  72. * console.log("sequence:", account.sequence);
  73. * });
  74. */
  75. async getAccount(address) {
  76. const ledgerKey = _stellarBase.xdr.LedgerKey.account(new _stellarBase.xdr.LedgerKeyAccount({
  77. accountId: _stellarBase.Keypair.fromPublicKey(address).xdrPublicKey()
  78. }));
  79. const resp = await this.getLedgerEntries(ledgerKey);
  80. if (resp.entries.length === 0) {
  81. return Promise.reject({
  82. code: 404,
  83. message: `Account not found: ${address}`
  84. });
  85. }
  86. const accountEntry = resp.entries[0].val.account();
  87. return new _stellarBase.Account(address, accountEntry.seqNum().toString());
  88. }
  89. /**
  90. * General node health check.
  91. *
  92. * @returns {Promise<SorobanRpc.GetHealthResponse>} a promise to the
  93. * {@link SorobanRpc.GetHealthResponse} object with the status of the
  94. * server (e.g. "healthy").
  95. *
  96. * @see https://soroban.stellar.org/api/methods/getHealth
  97. * @example
  98. * server.getHealth().then((health) => {
  99. * console.log("status:", health.status);
  100. * });
  101. */
  102. async getHealth() {
  103. return jsonrpc.post(this.serverURL.toString(), 'getHealth');
  104. }
  105. /**
  106. * Reads the current value of contract data ledger entries directly.
  107. *
  108. * Allows you to directly inspect the current state of a contract. This is a
  109. * backup way to access your contract data which may not be available via
  110. * events or {@link Server.simulateTransaction}.
  111. *
  112. * @param {string|Address|Contract} contract the contract ID containing the
  113. * data to load as a strkey (`C...` form), a {@link Contract}, or an
  114. * {@link Address} instance
  115. * @param {xdr.ScVal} key the key of the contract data to load
  116. * @param {Durability} [durability=Durability.Persistent] the "durability
  117. * keyspace" that this ledger key belongs to, which is either 'temporary'
  118. * or 'persistent' (the default), see {@link Durability}.
  119. *
  120. * @returns {Promise<SorobanRpc.LedgerEntryResult>} the current data value
  121. *
  122. * @warning If the data entry in question is a 'temporary' entry, it's
  123. * entirely possible that it has expired out of existence.
  124. *
  125. * @see https://soroban.stellar.org/api/methods/getLedgerEntries
  126. * @example
  127. * const contractId = "CCJZ5DGASBWQXR5MPFCJXMBI333XE5U3FSJTNQU7RIKE3P5GN2K2WYD5";
  128. * const key = xdr.ScVal.scvSymbol("counter");
  129. * server.getContractData(contractId, key, Durability.Temporary).then(data => {
  130. * console.log("value:", data.val);
  131. * console.log("liveUntilLedgerSeq:", data.liveUntilLedgerSeq);
  132. * console.log("lastModified:", data.lastModifiedLedgerSeq);
  133. * console.log("latestLedger:", data.latestLedger);
  134. * });
  135. */
  136. async getContractData(contract, key, durability = Durability.Persistent) {
  137. // coalesce `contract` param variants to an ScAddress
  138. let scAddress;
  139. if (typeof contract === 'string') {
  140. scAddress = new _stellarBase.Contract(contract).address().toScAddress();
  141. } else if (contract instanceof _stellarBase.Address) {
  142. scAddress = contract.toScAddress();
  143. } else if (contract instanceof _stellarBase.Contract) {
  144. scAddress = contract.address().toScAddress();
  145. } else {
  146. throw new TypeError(`unknown contract type: ${contract}`);
  147. }
  148. let xdrDurability;
  149. switch (durability) {
  150. case Durability.Temporary:
  151. xdrDurability = _stellarBase.xdr.ContractDataDurability.temporary();
  152. break;
  153. case Durability.Persistent:
  154. xdrDurability = _stellarBase.xdr.ContractDataDurability.persistent();
  155. break;
  156. default:
  157. throw new TypeError(`invalid durability: ${durability}`);
  158. }
  159. let contractKey = _stellarBase.xdr.LedgerKey.contractData(new _stellarBase.xdr.LedgerKeyContractData({
  160. key,
  161. contract: scAddress,
  162. durability: xdrDurability
  163. }));
  164. return this.getLedgerEntries(contractKey).then(r => {
  165. if (r.entries.length === 0) {
  166. return Promise.reject({
  167. code: 404,
  168. message: `Contract data not found. Contract: ${_stellarBase.Address.fromScAddress(scAddress).toString()}, Key: ${key.toXDR('base64')}, Durability: ${durability}`
  169. });
  170. }
  171. return r.entries[0];
  172. });
  173. }
  174. /**
  175. * Reads the current value of arbitrary ledger entries directly.
  176. *
  177. * Allows you to directly inspect the current state of contracts, contract's
  178. * code, accounts, or any other ledger entries.
  179. *
  180. * To fetch a contract's WASM byte-code, built the appropriate
  181. * {@link xdr.LedgerKeyContractCode} ledger entry key (or see
  182. * {@link Contract.getFootprint}).
  183. *
  184. * @param {xdr.ScVal[]} keys one or more ledger entry keys to load
  185. *
  186. * @returns {Promise<SorobanRpc.GetLedgerEntriesResponse>} the current
  187. * on-chain values for the given ledger keys
  188. *
  189. * @see Server._getLedgerEntries
  190. * @see https://soroban.stellar.org/api/methods/getLedgerEntries
  191. * @example
  192. * const contractId = "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM";
  193. * const key = xdr.LedgerKey.contractData(new xdr.LedgerKeyContractData({
  194. * contractId: StrKey.decodeContract(contractId),
  195. * key: xdr.ScVal.scvSymbol("counter"),
  196. * }));
  197. *
  198. * server.getLedgerEntries([key]).then(response => {
  199. * const ledgerData = response.entries[0];
  200. * console.log("key:", ledgerData.key);
  201. * console.log("value:", ledgerData.val);
  202. * console.log("liveUntilLedgerSeq:", ledgerData.liveUntilLedgerSeq);
  203. * console.log("lastModified:", ledgerData.lastModifiedLedgerSeq);
  204. * console.log("latestLedger:", response.latestLedger);
  205. * });
  206. */
  207. async getLedgerEntries(...keys) {
  208. return this._getLedgerEntries(...keys).then(_parsers.parseRawLedgerEntries);
  209. }
  210. async _getLedgerEntries(...keys) {
  211. return jsonrpc.post(this.serverURL.toString(), 'getLedgerEntries', keys.map(k => k.toXDR('base64')));
  212. }
  213. /**
  214. * Fetch the details of a submitted transaction.
  215. *
  216. * After submitting a transaction, clients should poll this to tell when the
  217. * transaction has completed.
  218. *
  219. * @param {string} hash hex-encoded hash of the transaction to check
  220. *
  221. * @returns {Promise<SorobanRpc.GetTransactionResponse>} the status,
  222. * result, and other details about the transaction
  223. *
  224. * @see https://soroban.stellar.org/api/methods/getTransaction
  225. * @example
  226. * const transactionHash = "c4515e3bdc0897f21cc5dbec8c82cf0a936d4741cb74a8e158eb51b9fb00411a";
  227. * server.getTransaction(transactionHash).then((tx) => {
  228. * console.log("status:", tx.status);
  229. * console.log("envelopeXdr:", tx.envelopeXdr);
  230. * console.log("resultMetaXdr:", tx.resultMetaXdr);
  231. * console.log("resultXdr:", tx.resultXdr);
  232. * });
  233. */
  234. async getTransaction(hash) {
  235. return this._getTransaction(hash).then(raw => {
  236. let successInfo = {};
  237. if (raw.status === _soroban_rpc.SorobanRpc.GetTransactionStatus.SUCCESS) {
  238. var _meta$v3$sorobanMeta;
  239. const meta = _stellarBase.xdr.TransactionMeta.fromXDR(raw.resultMetaXdr, 'base64');
  240. successInfo = {
  241. ledger: raw.ledger,
  242. createdAt: raw.createdAt,
  243. applicationOrder: raw.applicationOrder,
  244. feeBump: raw.feeBump,
  245. envelopeXdr: _stellarBase.xdr.TransactionEnvelope.fromXDR(raw.envelopeXdr, 'base64'),
  246. resultXdr: _stellarBase.xdr.TransactionResult.fromXDR(raw.resultXdr, 'base64'),
  247. resultMetaXdr: meta,
  248. ...(meta.switch() === 3 && meta.v3().sorobanMeta() !== null && {
  249. returnValue: (_meta$v3$sorobanMeta = meta.v3().sorobanMeta()) === null || _meta$v3$sorobanMeta === void 0 ? void 0 : _meta$v3$sorobanMeta.returnValue()
  250. })
  251. };
  252. }
  253. const result = {
  254. status: raw.status,
  255. latestLedger: raw.latestLedger,
  256. latestLedgerCloseTime: raw.latestLedgerCloseTime,
  257. oldestLedger: raw.oldestLedger,
  258. oldestLedgerCloseTime: raw.oldestLedgerCloseTime,
  259. ...successInfo
  260. };
  261. return result;
  262. });
  263. }
  264. async _getTransaction(hash) {
  265. return jsonrpc.post(this.serverURL.toString(), 'getTransaction', hash);
  266. }
  267. /**
  268. * Fetch all events that match a given set of filters.
  269. *
  270. * The given filters (see {@link SorobanRpc.EventFilter} for detailed fields)
  271. * are combined only in a logical OR fashion, and all of the fields in each
  272. * filter are optional.
  273. *
  274. * To page through events, use the `pagingToken` field on the relevant
  275. * {@link SorobanRpc.EventResponse} object to set the `cursor` parameter.
  276. *
  277. * @param {Server.GetEventsRequest} request event filters
  278. * @returns {Promise<SorobanRpc.GetEventsResponse>} a paginatable set of the
  279. * events matching the given event filters
  280. *
  281. * @see https://soroban.stellar.org/api/methods/getEvents
  282. * @example
  283. * server.getEvents({
  284. * startLedger: 1000,
  285. * filters: [
  286. * {
  287. * type: "contract",
  288. * contractIds: [ "deadb33f..." ],
  289. * topics: [[ "AAAABQAAAAh0cmFuc2Zlcg==", "AAAAAQB6Mcc=", "*" ]]
  290. * }, {
  291. * type: "system",
  292. * contractIds: [ "...c4f3b4b3..." ],
  293. * topics: [[ "*" ], [ "*", "AAAAAQB6Mcc=" ]]
  294. * }, {
  295. * contractIds: [ "...c4f3b4b3..." ],
  296. * topics: [[ "AAAABQAAAAh0cmFuc2Zlcg==" ]]
  297. * }, {
  298. * type: "diagnostic",
  299. * topics: [[ "AAAAAQB6Mcc=" ]]
  300. * }
  301. * ],
  302. * limit: 10,
  303. * });
  304. */
  305. async getEvents(request) {
  306. return this._getEvents(request).then(_parsers.parseRawEvents);
  307. }
  308. async _getEvents(request) {
  309. return jsonrpc.postObject(this.serverURL.toString(), 'getEvents', {
  310. filters: request.filters ?? [],
  311. pagination: {
  312. ...(request.cursor && {
  313. cursor: request.cursor
  314. }),
  315. // add if defined
  316. ...(request.limit && {
  317. limit: request.limit
  318. })
  319. },
  320. ...(request.startLedger && {
  321. startLedger: request.startLedger
  322. })
  323. });
  324. }
  325. /**
  326. * Fetch metadata about the network this Soroban RPC server is connected to.
  327. *
  328. * @returns {Promise<SorobanRpc.GetNetworkResponse>} metadata about the
  329. * current network this RPC server is connected to
  330. *
  331. * @see https://soroban.stellar.org/api/methods/getNetwork
  332. * @example
  333. * server.getNetwork().then((network) => {
  334. * console.log("friendbotUrl:", network.friendbotUrl);
  335. * console.log("passphrase:", network.passphrase);
  336. * console.log("protocolVersion:", network.protocolVersion);
  337. * });
  338. */
  339. async getNetwork() {
  340. return await jsonrpc.post(this.serverURL.toString(), 'getNetwork');
  341. }
  342. /**
  343. * Fetch the latest ledger meta info from network which this Soroban RPC
  344. * server is connected to.
  345. *
  346. * @returns {Promise<SorobanRpc.GetLatestLedgerResponse>} metadata about the
  347. * latest ledger on the network that this RPC server is connected to
  348. *
  349. * @see https://soroban.stellar.org/api/methods/getLatestLedger
  350. * @example
  351. * server.getLatestLedger().then((response) => {
  352. * console.log("hash:", response.id);
  353. * console.log("sequence:", response.sequence);
  354. * console.log("protocolVersion:", response.protocolVersion);
  355. * });
  356. */
  357. async getLatestLedger() {
  358. return jsonrpc.post(this.serverURL.toString(), 'getLatestLedger');
  359. }
  360. /**
  361. * Submit a trial contract invocation to get back return values, expected
  362. * ledger footprint, expected authorizations, and expected costs.
  363. *
  364. * @param {Transaction | FeeBumpTransaction} transaction the transaction to
  365. * simulate, which should include exactly one operation (one of
  366. * {@link xdr.InvokeHostFunctionOp}, {@link xdr.ExtendFootprintTTLOp},
  367. * or {@link xdr.RestoreFootprintOp}). Any provided footprint or auth
  368. * information will be ignored.
  369. *
  370. * @returns {Promise<SorobanRpc.SimulateTransactionResponse>} an object with
  371. * the cost, footprint, result/auth requirements (if applicable), and error
  372. * of the transaction
  373. *
  374. * @see https://developers.stellar.org/docs/glossary/transactions/
  375. * @see https://soroban.stellar.org/api/methods/simulateTransaction
  376. * @see Server.prepareTransaction
  377. * @see assembleTransaction
  378. *
  379. * @example
  380. * const contractId = 'CA3D5KRYM6CB7OWQ6TWYRR3Z4T7GNZLKERYNZGGA5SOAOPIFY6YQGAXE';
  381. * const contract = new SorobanClient.Contract(contractId);
  382. *
  383. * // Right now, this is just the default fee for this example.
  384. * const fee = SorobanClient.BASE_FEE;
  385. * const transaction = new SorobanClient.TransactionBuilder(account, { fee })
  386. * // Uncomment the following line to build transactions for the live network. Be
  387. * // sure to also change the horizon hostname.
  388. * //.setNetworkPassphrase(SorobanClient.Networks.PUBLIC)
  389. * .setNetworkPassphrase(SorobanClient.Networks.FUTURENET)
  390. * .setTimeout(30) // valid for the next 30s
  391. * // Add an operation to call increment() on the contract
  392. * .addOperation(contract.call("increment"))
  393. * .build();
  394. *
  395. * server.simulateTransaction(transaction).then((sim) => {
  396. * console.log("cost:", sim.cost);
  397. * console.log("result:", sim.result);
  398. * console.log("error:", sim.error);
  399. * console.log("latestLedger:", sim.latestLedger);
  400. * });
  401. */
  402. async simulateTransaction(transaction) {
  403. return this._simulateTransaction(transaction).then(_parsers.parseRawSimulation);
  404. }
  405. async _simulateTransaction(transaction) {
  406. return jsonrpc.post(this.serverURL.toString(), 'simulateTransaction', transaction.toXDR());
  407. }
  408. /**
  409. * Submit a trial contract invocation, first run a simulation of the contract
  410. * invocation as defined on the incoming transaction, and apply the results to
  411. * a new copy of the transaction which is then returned. Setting the ledger
  412. * footprint and authorization, so the resulting transaction is ready for
  413. * signing & sending.
  414. *
  415. * The returned transaction will also have an updated fee that is the sum of
  416. * fee set on incoming transaction with the contract resource fees estimated
  417. * from simulation. It is adviseable to check the fee on returned transaction
  418. * and validate or take appropriate measures for interaction with user to
  419. * confirm it is acceptable.
  420. *
  421. * You can call the {@link Server.simulateTransaction} method directly first
  422. * if you want to inspect estimated fees for a given transaction in detail
  423. * first, then re-assemble it manually or via {@link assembleTransaction}.
  424. *
  425. * @param {Transaction | FeeBumpTransaction} transaction the transaction to
  426. * prepare. It should include exactly one operation, which must be one of
  427. * {@link xdr.InvokeHostFunctionOp}, {@link xdr.ExtendFootprintTTLOp},
  428. * or {@link xdr.RestoreFootprintOp}.
  429. *
  430. * Any provided footprint will be overwritten. However, if your operation
  431. * has existing auth entries, they will be preferred over ALL auth entries
  432. * from the simulation. In other words, if you include auth entries, you
  433. * don't care about the auth returned from the simulation. Other fields
  434. * (footprint, etc.) will be filled as normal.
  435. * @param {string} [networkPassphrase] explicitly provide a network
  436. * passphrase (default: requested from the server via
  437. * {@link Server.getNetwork}).
  438. *
  439. * @returns {Promise<Transaction | FeeBumpTransaction>} a copy of the
  440. * transaction with the expected authorizations (in the case of
  441. * invocation), resources, and ledger footprints added. The transaction fee
  442. * will also automatically be padded with the contract's minimum resource
  443. * fees discovered from the simulation.
  444. *
  445. * @see assembleTransaction
  446. * @see https://soroban.stellar.org/api/methods/simulateTransaction
  447. * @throws {jsonrpc.Error<any> | Error} if simulation fails
  448. * @example
  449. * const contractId = 'CA3D5KRYM6CB7OWQ6TWYRR3Z4T7GNZLKERYNZGGA5SOAOPIFY6YQGAXE';
  450. * const contract = new SorobanClient.Contract(contractId);
  451. *
  452. * // Right now, this is just the default fee for this example.
  453. * const fee = SorobanClient.BASE_FEE;
  454. * const transaction = new SorobanClient.TransactionBuilder(account, { fee })
  455. * // Uncomment the following line to build transactions for the live network. Be
  456. * // sure to also change the horizon hostname.
  457. * //.setNetworkPassphrase(SorobanClient.Networks.PUBLIC)
  458. * .setNetworkPassphrase(SorobanClient.Networks.FUTURENET)
  459. * .setTimeout(30) // valid for the next 30s
  460. * // Add an operation to call increment() on the contract
  461. * .addOperation(contract.call("increment"))
  462. * .build();
  463. *
  464. * const preparedTransaction = await server.prepareTransaction(transaction);
  465. *
  466. * // Sign this transaction with the secret key
  467. * // NOTE: signing is transaction is network specific. Test network transactions
  468. * // won't work in the public network. To switch networks, use the Network object
  469. * // as explained above (look for SorobanClient.Network).
  470. * const sourceKeypair = SorobanClient.Keypair.fromSecret(sourceSecretKey);
  471. * preparedTransaction.sign(sourceKeypair);
  472. *
  473. * server.sendTransaction(transaction).then(result => {
  474. * console.log("hash:", result.hash);
  475. * console.log("status:", result.status);
  476. * console.log("errorResultXdr:", result.errorResultXdr);
  477. * });
  478. */
  479. async prepareTransaction(transaction, networkPassphrase) {
  480. const [{
  481. passphrase
  482. }, simResponse] = await Promise.all([networkPassphrase ? Promise.resolve({
  483. passphrase: networkPassphrase
  484. }) : this.getNetwork(), this.simulateTransaction(transaction)]);
  485. if (_soroban_rpc.SorobanRpc.isSimulationError(simResponse)) {
  486. throw simResponse.error;
  487. }
  488. if (!simResponse.result) {
  489. throw new Error('transaction simulation failed');
  490. }
  491. return (0, _transaction.assembleTransaction)(transaction, passphrase, simResponse).build();
  492. }
  493. /**
  494. * Submit a real transaction to the Stellar network.
  495. *
  496. * Unlike Horizon, Soroban RPC does not wait for transaction completion. It
  497. * simply validates the transaction and enqueues it. Clients should call
  498. * {@link Server.getTransactionStatus} to learn about transaction
  499. * success/failure.
  500. *
  501. * @param {Transaction | FeeBumpTransaction} transaction to submit
  502. * @returns {Promise<SorobanRpc.SendTransactionResponse>} the
  503. * transaction id, status, and any error if available
  504. *
  505. * @see https://developers.stellar.org/docs/glossary/transactions/
  506. * @see https://soroban.stellar.org/api/methods/sendTransaction
  507. * @example
  508. * const contractId = 'CA3D5KRYM6CB7OWQ6TWYRR3Z4T7GNZLKERYNZGGA5SOAOPIFY6YQGAXE';
  509. * const contract = new SorobanClient.Contract(contractId);
  510. *
  511. * // Right now, this is just the default fee for this example.
  512. * const fee = SorobanClient.BASE_FEE;
  513. * const transaction = new SorobanClient.TransactionBuilder(account, { fee })
  514. * // Uncomment the following line to build transactions for the live network. Be
  515. * // sure to also change the horizon hostname.
  516. * //.setNetworkPassphrase(SorobanClient.Networks.PUBLIC)
  517. * .setNetworkPassphrase(SorobanClient.Networks.FUTURENET)
  518. * .setTimeout(30) // valid for the next 30s
  519. * // Add an operation to call increment() on the contract
  520. * .addOperation(contract.call("increment"))
  521. * .build();
  522. *
  523. * // Sign this transaction with the secret key
  524. * // NOTE: signing is transaction is network specific. Test network transactions
  525. * // won't work in the public network. To switch networks, use the Network object
  526. * // as explained above (look for SorobanClient.Network).
  527. * const sourceKeypair = SorobanClient.Keypair.fromSecret(sourceSecretKey);
  528. * transaction.sign(sourceKeypair);
  529. *
  530. * server.sendTransaction(transaction).then((result) => {
  531. * console.log("hash:", result.hash);
  532. * console.log("status:", result.status);
  533. * console.log("errorResultXdr:", result.errorResultXdr);
  534. * });
  535. */
  536. async sendTransaction(transaction) {
  537. return this._sendTransaction(transaction).then(_parsers.parseRawSendTransaction);
  538. }
  539. async _sendTransaction(transaction) {
  540. return jsonrpc.post(this.serverURL.toString(), 'sendTransaction', transaction.toXDR());
  541. }
  542. /**
  543. * Fund a new account using the network's friendbot faucet, if any.
  544. *
  545. * @param {string | Account} address the address or account instance that we
  546. * want to create and fund with friendbot
  547. * @param {string} [friendbotUrl] optionally, an explicit address for
  548. * friendbot (by default: this calls the Soroban RPC
  549. * {@link Server.getNetwork} method to try to discover this network's
  550. * Friendbot url).
  551. *
  552. * @returns {Promise<Account>} an {@link Account} object for the created
  553. * account, or the existing account if it's already funded with the
  554. * populated sequence number (note that the account will not be "topped
  555. * off" if it already exists)
  556. *
  557. * @throws if Friendbot is not configured on this network or request failure
  558. *
  559. * @see
  560. * https://developers.stellar.org/docs/fundamentals-and-concepts/testnet-and-pubnet#friendbot
  561. * @see Friendbot.Response
  562. * @example
  563. * server
  564. * .requestAirdrop("GBZC6Y2Y7Q3ZQ2Y4QZJ2XZ3Z5YXZ6Z7Z2Y4QZJ2XZ3Z5YXZ6Z7Z2Y4")
  565. * .then((accountCreated) => {
  566. * console.log("accountCreated:", accountCreated);
  567. * }).catch((error) => {
  568. * console.error("error:", error);
  569. * });
  570. */
  571. async requestAirdrop(address, friendbotUrl) {
  572. const account = typeof address === 'string' ? address : address.accountId();
  573. friendbotUrl = friendbotUrl || (await this.getNetwork()).friendbotUrl;
  574. if (!friendbotUrl) {
  575. throw new Error('No friendbot URL configured for current network');
  576. }
  577. try {
  578. const response = await _axios.default.post(`${friendbotUrl}?addr=${encodeURIComponent(account)}`);
  579. const meta = _stellarBase.xdr.TransactionMeta.fromXDR(response.data.result_meta_xdr, 'base64');
  580. const sequence = findCreatedAccountSequenceInTransactionMeta(meta);
  581. return new _stellarBase.Account(account, sequence);
  582. } catch (error) {
  583. var _error$response;
  584. if (((_error$response = error.response) === null || _error$response === void 0 ? void 0 : _error$response.status) === 400) {
  585. var _error$response$detai;
  586. if ((_error$response$detai = error.response.detail) !== null && _error$response$detai !== void 0 && _error$response$detai.includes('createAccountAlreadyExist')) {
  587. // Account already exists, load the sequence number
  588. return this.getAccount(account);
  589. }
  590. }
  591. throw error;
  592. }
  593. }
  594. }
  595. exports.Server = Server;
  596. function findCreatedAccountSequenceInTransactionMeta(meta) {
  597. let operations = [];
  598. switch (meta.switch()) {
  599. case 0:
  600. operations = meta.operations();
  601. break;
  602. case 1:
  603. case 2:
  604. case 3:
  605. // all three have the same interface
  606. operations = meta.value().operations();
  607. break;
  608. default:
  609. throw new Error('Unexpected transaction meta switch value');
  610. }
  611. for (const op of operations) {
  612. for (const c of op.changes()) {
  613. if (c.switch() !== _stellarBase.xdr.LedgerEntryChangeType.ledgerEntryCreated()) {
  614. continue;
  615. }
  616. const data = c.created().data();
  617. if (data.switch() !== _stellarBase.xdr.LedgerEntryType.account()) {
  618. continue;
  619. }
  620. return data.account().seqNum().toString();
  621. }
  622. }
  623. throw new Error('No account created in transaction');
  624. }