UNPKG

@parifi/synthetix-sdk-ts

Version:

A Typescript SDK for interactions with the Synthetix protocol

796 lines (786 loc) 27.4 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/utils/index.ts var utils_exports = {}; __export(utils_exports, { Utils: () => Utils, batchArray: () => batchArray, convertEtherToWei: () => convertEtherToWei, convertWeiToEther: () => convertWeiToEther, fetcher: () => fetcher, generateRandomAccountId: () => generateRandomAccountId, getChain: () => getChain, getOdosPath: () => getOdosPath, getPublicRpcEndpoint: () => getPublicRpcEndpoint, sleep: () => sleep }); module.exports = __toCommonJS(utils_exports); // src/utils/common.ts var import_viem3 = require("viem"); var import_chains3 = require("viem/chains"); var import_crypto = require("crypto"); // src/constants/common.ts var import_viem = require("viem"); var SIG_ORACLE_DATA_REQUIRED = "0xcf2cabdf"; var SIG_FEE_REQUIRED = "0x0e7186fb"; var SIG_ERRORS = "0x0b42fd17"; var MAX_ERC7412_RETRIES = 80; var publicRpcEndpoints = { 8453: "https://base.llamarpc.com", 84532: "https://sepolia.base.org", 42161: "https://arbitrum.llamarpc.com", 421614: "https://sepolia-rollup.arbitrum.io/rpc" }; var CUSTOM_DECIMALS = { [421614 /* ARBITUM_SEPOLIA */]: { 2: 6, USDC: 6 }, [42161 /* ARBITRUM */]: { 2: 6, USDC: 6 }, [84532 /* BASE_SEPOLIA */]: { 1: 6, USDC: 6 }, [8453 /* BASE */]: { 1: 6, USDC: 6 } }; // src/contracts/addreses/zap.ts var import_viem2 = require("viem"); var ZAP_BY_CHAIN = { [8453 /* BASE */]: "0x459Bbb4231f0a606DC514BacD5712A5922CBe6c8", [84532 /* BASE_SEPOLIA */]: import_viem2.zeroAddress, [42161 /* ARBITRUM */]: "0x9ec181B2E69fB36C50031F0c87Bc0749b766A9f4", [421614 /* ARBITUM_SEPOLIA */]: "0xb569ed692206a1d73996088ae646333b1d59d9c5" }; var SYNTHETIX_ZAP = { [84532 /* BASE_SEPOLIA */]: "0xA6Fab50eB36F3eB2118eE2f4C12C968F8608bbc9", [8453 /* BASE */]: "0xA6Fab50eB36F3eB2118eE2f4C12C968F8608bbc9" }; // src/utils/common.ts function getPublicRpcEndpoint(chainId) { return publicRpcEndpoints[chainId]; } function getChain(chainId) { const chains = [import_chains3.mainnet, import_chains3.base, import_chains3.optimism, import_chains3.arbitrum, import_chains3.baseSepolia, import_chains3.arbitrumSepolia]; for (const chain of Object.values(chains)) { if (chain.id === chainId) { return chain; } } throw new Error(`Chain with id ${chainId} not found`); } function convertWeiToEther(amountInWei) { if (amountInWei == void 0) { throw new Error("Invalid amount received during conversion: undefined"); } if (typeof amountInWei == "bigint") { return Number((0, import_viem3.formatEther)(amountInWei)); } else if (typeof amountInWei == "string") { return Number((0, import_viem3.formatEther)(BigInt(amountInWei))); } else { throw new Error("Expected string or bigint for conversion"); } } function convertEtherToWei(amount) { if (amount == void 0) { throw new Error("Invalid amount received during conversion: undefined"); } if (typeof amount == "number") { return (0, import_viem3.parseEther)(amount.toString()); } else if (typeof amount == "string") { return (0, import_viem3.parseEther)(amount); } else { throw new Error("Expected string or bigint for conversion"); } } function sleep(seconds) { return new Promise((resolve) => setTimeout(resolve, seconds * 1e3)); } function generateRandomAccountId() { const maxUint128Half = import_viem3.maxUint128 / BigInt(2); const buffer = (0, import_crypto.randomBytes)(8); const randomAccountId = BigInt("0x" + buffer.toString("hex")); if (randomAccountId > maxUint128Half) { throw new Error("Account ID greater than Maxuint128"); } return randomAccountId; } var batchArray = (arr, batchSize) => { return arr.reduce((acc, _, i) => i % batchSize ? acc : [...acc, arr.slice(i, i + batchSize)], []); }; var fetcher = (url, init = { headers: { "Content-Type": "application/json" } }) => fetch(url, { ...init, body: JSON.stringify(init.body), headers: init.headers, method: init.body && !init.method ? "POST" : init.method }); var odoFetcher = async (url, options) => { return fetcher(`https://api.odos.xyz/sor${url}`, options); }; var assemblePath = async (user, pathId) => { const response = await odoFetcher(`/assemble`, { body: { userAddr: user, pathId }, headers: { "Content-Type": "application/json" } }); if (!response.ok) return ""; const data = await response.json(); return data.transaction.data; }; var getOdosPath = async (quoteParams) => { if (!quoteParams.fromToken || !quoteParams.toToken || !quoteParams.fromAmount) { throw new Error("Missing required parameters for Odos path generation"); } const data = { chainId: quoteParams.fromChain, inputTokens: [{ tokenAddress: quoteParams.fromToken, amount: quoteParams.fromAmount }], outputTokens: [{ tokenAddress: quoteParams.toToken, proportion: 1 }], userAddr: ZAP_BY_CHAIN[quoteParams.fromChain] }; const response = await odoFetcher("/quote/v2", { body: data, headers: { "Content-Type": "application/json" } }); if (!response.ok) { console.error(`Failed to get Odos quote: ${response.status} ${response.statusText}`); return { path: "" }; } const quote = await response.json(); if (!quote?.pathId) { console.error("Invalid response from Odos API: missing pathId"); return { path: "" }; } const quoteId = quote.pathId; const path = await assemblePath(data.userAddr, quoteId); if (!path) { console.error("Failed to assemble path from pathId"); } return { path }; }; // src/utils/index.ts var import_viem4 = require("viem"); // src/contracts/abis/IERC7412.ts var IERC7412Abi = [ { type: "function", name: "fulfillOracleQuery", inputs: [{ name: "signedOffchainData", type: "bytes", internalType: "bytes" }], outputs: [], stateMutability: "payable" }, { type: "function", name: "oracleId", inputs: [], outputs: [{ name: "", type: "bytes32", internalType: "bytes32" }], stateMutability: "view" }, { type: "error", name: "FeeRequired", inputs: [{ name: "feeAmount", type: "uint256", internalType: "uint256" }] }, { type: "error", name: "OracleDataRequired", inputs: [ { name: "oracleContract", type: "address", internalType: "address" }, { name: "oracleQuery", type: "bytes", internalType: "bytes" } ] }, { type: "error", name: "Errors", inputs: [ { type: "bytes[]", name: "revertReasons" } ] } ]; // src/utils/parseError.ts function parseError(error) { try { if (error.cause?.data) { return error.cause?.data; } if (error.cause?.cause?.data) { return error.cause?.cause?.data; } if (error.cause?.cause?.cause?.data) { return error.cause?.cause?.cause?.data; } if (error.cause?.cause?.error?.data) { return error.cause?.cause?.error?.data; } if (error.cause?.cause?.cause?.error?.data) { return error.cause?.cause?.cause?.error?.data; } } catch (err) { console.log("=== exception in erc7412 error parser:", err); } console.log("=== a", JSON.stringify(error, null, 2)); console.error("=== got unknown error in erc7412 parse", error); return "0x"; } // src/contracts/addreses/oracleProxy.ts var ORACLE_PROXY_BY_CHAIN = { [421614 /* ARBITUM_SEPOLIA */]: "0x59d6ec32e05900949d7fff679a4adc7f94f0208c", [42161 /* ARBITRUM */]: "0xe87ceB87b63267ef925E2897B629052eb815bB7d", [8453 /* BASE */]: "0xa03A0Be2f3B85B76765A442683d62E992972d816", [84532 /* BASE_SEPOLIA */]: "0x4Bc47c016EE6Ead253152CCfe6427D0bC06F544c" }; // src/utils/index.ts var Utils = class { constructor(synthetixSdk) { this.sdk = synthetixSdk; } async isOracleCall(data) { return Object.values(ORACLE_PROXY_BY_CHAIN).map((a) => a.toLowerCase()).includes(typeof data === "string" ? data.toLowerCase() : data.to.toLowerCase()); } /** * Returns the Pyth price ids array * @param oracleQueryData * @returns Pyth Price IDs array */ getPythPriceIdsFromOracleQuery(oracleQueryData) { const values = (0, import_viem4.decodeAbiParameters)((0, import_viem4.parseAbiParameters)("uint8, uint64, bytes32[]"), oracleQueryData); return values[2]; } /** * Decodes the response from a Smart contract function call * @param abi Contract ABI * @param functionName Function name to decode * @param result Response from function call that needs to be decoded * @returns Decoded result */ decodeResponse(abi, functionName, result) { const decodedResult = (0, import_viem4.decodeFunctionResult)({ abi, functionName, data: result }); return decodedResult; } /** * Determines the type of Error emitted by ERC7412 contract and prepares signed update data * @param data Error data emitted from ERC7412 contract * @returns Encoded data for oracle price update transaction */ async fetchOracleUpdateData(data) { const [updateType] = (0, import_viem4.decodeAbiParameters)([{ name: "updateType", type: "uint8" }], data); if (updateType === 1) { const [updateType2, stalenessOrTime, priceIds] = (0, import_viem4.decodeAbiParameters)( [ { name: "updateType", type: "uint8" }, { name: "stalenessTolerance", type: "uint64" }, { name: "priceIds", type: "bytes32[]" } ], data ); const stalenessTolerance = stalenessOrTime; const updateData = await this.sdk.pyth.pythConnection.getPriceFeedsUpdateData( priceIds ); return (0, import_viem4.encodeAbiParameters)( [ { type: "uint8", name: "updateType" }, { type: "uint64", name: "stalenessTolerance" }, { type: "bytes32[]", name: "priceIds" }, { type: "bytes[]", name: "updateData" } ], [updateType2, stalenessTolerance, priceIds, updateData] ); } else if (updateType === 2) { const [updateType2, requestedTime, priceId] = (0, import_viem4.decodeAbiParameters)( [ { name: "updateType", type: "uint8" }, { name: "requestedTime", type: "uint64" }, { name: "priceIds", type: "bytes32" } ], data ); this.sdk.logger.info("Update type: ", updateType2); this.sdk.logger.info("priceIds: ", priceId); const [priceFeedUpdateVaa] = await this.sdk.pyth.pythConnection.getVaa( priceId, Number(requestedTime.toString()) ); const priceFeedUpdate = "0x" + Buffer.from(priceFeedUpdateVaa, "base64").toString("hex"); return (0, import_viem4.encodeAbiParameters)( [ { type: "uint8", name: "updateType" }, { type: "uint64", name: "timestamp" }, { type: "bytes32[]", name: "priceIds" }, { type: "bytes[]", name: "updateData" } ], [updateType2, requestedTime, [priceId], [priceFeedUpdate]] ); } else { throw new Error(`Error encoding/decoding data`); } } async handleOracleDataRequiredError(parsedError) { const err = (0, import_viem4.decodeErrorResult)({ abi: IERC7412Abi, data: parsedError }); const oracleAddress = err.args[0]; const oracleQuery = err.args[1]; const signedRequiredData = await this.fetchOracleUpdateData(oracleQuery); const dataVerificationTx = this.generateDataVerificationTx(oracleAddress, signedRequiredData); return dataVerificationTx; } /** * Handles ERC7412 error by creating a price update tx which is prepended to the existing calls * @param error Error thrown by the call function * @param calls Multicall call data * @returns call array with ERC7412 fulfillOracleQuery transaction */ async handleErc7412Error(parsedError) { let err; try { err = (0, import_viem4.decodeErrorResult)({ abi: IERC7412Abi, data: parsedError }); } catch (decodeErr) { this.sdk.logger.error("Decode Error: ", decodeErr); throw new Error("Handle ERC7412 error"); } if (!["OracleDataRequired", "FeeRequired", "Errors"].includes(err?.errorName)) throw new Error("Handle ERC7412 error"); if (err?.errorName === "Errors") { const oracleErrors = err.args[0]; let oracleCalls = []; const batchedOracleErrors = batchArray(oracleErrors, 10); for (const oracleErrors2 of batchedOracleErrors) { const promiseOracleCalls = oracleErrors2.map((oracleError) => { return this.handleErc7412Error(oracleError); }); const resolvedCalls = await Promise.all(promiseOracleCalls); oracleCalls = [...oracleCalls, ...resolvedCalls.flat()]; } return oracleCalls.flat(); } if (err?.errorName === "OracleDataRequired") { return [await this.handleOracleDataRequiredError(parsedError)]; } return []; } /** * Generates Call3Value tx for Price update data of Oracle * @param oracleContract Oracle Contract address * @param signedRequiredData Encoded Price Update data * @returns Transaction Request for Oracle price update */ generateDataVerificationTx(_oracleContract, signedRequiredData) { const priceUpdateCall = { target: ORACLE_PROXY_BY_CHAIN[this.sdk.rpcConfig.chainId], callData: (0, import_viem4.encodeFunctionData)({ abi: IERC7412Abi, functionName: "fulfillOracleQuery", args: [signedRequiredData] }), value: 0n, requireSuccess: false }; return priceUpdateCall; } /** * Calls the `functionName` on `contractAddress` target using the Multicall contract. If the call requires * a price update, ERC7412 price update tx is prepended to the tx. * @param contractAddress Target contract address for the call * @param abi Contract ABI * @param functionName Function to be called on the contract * @param args Arguments list for the function call * @param calls Array of Call3Value calls for Multicall contract * @returns Response from the contract function call */ async callErc7412({ contractAddress, abi, args, functionName, calls = [] }) { const multicallInstance = await this.sdk.contracts.getMulticallInstance(); const currentCall = { target: contractAddress, callData: (0, import_viem4.encodeFunctionData)({ abi, functionName, args }), value: 0n, requireSuccess: true }; calls.push(currentCall); const publicClient = this.sdk.getPublicClient(); const oracleCalls = await this.getMissingOracleCalls(calls); const multicallData = (0, import_viem4.encodeFunctionData)({ abi: multicallInstance.abi, functionName: "aggregate3Value", args: [[...oracleCalls, ...calls]] }); const totalValue = [...oracleCalls, ...calls].reduce((acc, tx) => { return acc + (tx.value || 0n); }, 0n); const finalTx = { account: this.sdk.accountAddress, to: multicallInstance.address, data: multicallData, value: totalValue }; const response = await publicClient.call(finalTx); this.sdk.logger.info("=== response", response); if (!response.data) throw new Error("Error decoding call data"); const multicallResult = this.decodeResponse( multicallInstance.abi, "aggregate3Value", response.data ); const returnData = multicallResult.at(-1); if (!returnData?.success) throw new Error("Error decoding call data"); const decodedResult = this.decodeResponse(abi, functionName, returnData.returnData); return decodedResult; } /** * Calls the `functionName` on `contractAddress` target using the Multicall contract. If the call requires * a price update, ERC7412 price update tx is prepended to the tx. * @param contractAddress Target contract address for the call * @param abi Contract ABI * @param functionName Function to be called on the contract * @param argsList Array of arguments list for the function call * @param calls Array of Call3Value calls for Multicall contract * @returns Array of responses from the contract function call for the multicalls */ async multicallErc7412({ contractAddress, abi, functionName, args: argsList, calls = [] }) { const multicallInstance = await this.sdk.contracts.getMulticallInstance(); argsList = argsList.map((args) => Array.isArray(args) ? args : [args]); argsList.forEach((args) => { const currentCall = { target: contractAddress, callData: (0, import_viem4.encodeFunctionData)({ abi, functionName, args }), value: 0n, requireSuccess: true }; calls.push(currentCall); }); calls = calls.map((call) => { return { ...call, requireSuccess: call.value === 0n ? true : false }; }); const oracleCalls = await this.getMissingOracleCalls(calls); const numCalls = calls.length - oracleCalls.length; const publicClient = this.sdk.getPublicClient(); const totalValue = [...oracleCalls, ...calls].reduce((acc, tx) => { return acc + (tx.value || 0n); }, 0n); const multicallData = (0, import_viem4.encodeFunctionData)({ abi: multicallInstance.abi, functionName: "aggregate3Value", args: [[...oracleCalls, ...calls]] }); const finalTx = { account: this.sdk.accountAddress, to: multicallInstance.address, data: multicallData, value: totalValue }; const response = await publicClient.call(finalTx); const multicallResult = this.decodeResponse( multicallInstance.abi, "aggregate3Value", response.data ); const callsToDecode = multicallResult.slice(-numCalls); const decodedResult = callsToDecode.map((result) => this.decodeResponse(abi, functionName, result.returnData)); return decodedResult; } isWriteContractParams(data) { return data.contractAddress !== void 0; } /** * Simulates the `functionName` on `contractAddress` target using the Multicall contract and returns the * final transaction call with ERC7412 price update data if required * @param contractAddress Target contract address for the call * @param abi Contract ABI * @param functionName Function to be called on the contract * @param args Arguments list for the function call * @param calls Array of Call3Value calls for Multicall contract * @param override Override parameters for the transaction * @returns Final transaction call with ERC7412 price update data if required */ async writeErc7412(data, override = { shouldRevertOnTxFailure: true }) { const calls = data.calls ?? []; const multicallInstance = await this.sdk.contracts.getMulticallInstance(); if (this.isWriteContractParams(data)) { const { contractAddress, abi, functionName, args } = data; const currentCall = { target: contractAddress, callData: (0, import_viem4.encodeFunctionData)({ abi, functionName, args }), value: 0n, requireSuccess: true }; calls.push(currentCall); } const multicallData = (0, import_viem4.encodeFunctionData)({ abi: multicallInstance.abi, functionName: "aggregate3Value", args: [calls] }); let totalValue = 0n; for (const tx of calls) { totalValue += tx.value || 0n; } const finalTx = { account: override.account || this.sdk.accountAddress, to: multicallInstance.address, data: multicallData, value: totalValue }; const publicClient = this.sdk.getPublicClient(); if (override.shouldRevertOnTxFailure) await publicClient.call(finalTx); return this._fromCallDataToTransactionData(finalTx); } /** * Calls the `functionName` on `contractAddress` target using the Multicall contract. If the call requires * a price update, ERC7412 price update tx is prepended to the tx. * @param contractAddress Target contract address for the call * @param abi Contract ABI * @param functionNames Function to be called on the contract * @param argsList Array of arguments list for the function call * @param calls Array of Call3Value calls for Multicall contract * @returns Array of responses from the contract function call for the multicalls */ async multicallMultifunctionErc7412({ contractAddress, abi, functionNames, args: argsList, calls = [] }, override = {}) { const multicallInstance = await this.sdk.contracts.getMulticallInstance(); argsList = argsList.map((args) => Array.isArray(args) ? args : [args]); if (argsList.length != functionNames.length) { throw new Error("Inconsistent data: args and functionName don't match"); } argsList.forEach((args, index) => { const currentCall = { target: contractAddress, callData: (0, import_viem4.encodeFunctionData)({ abi, functionName: functionNames[index], args }), value: 0n, requireSuccess: true }; calls.push(currentCall); }); const publicClient = this.sdk.getPublicClient(); const oracleCalls = await this.getMissingOracleCalls(calls); const multicallData = (0, import_viem4.encodeFunctionData)({ abi: multicallInstance.abi, functionName: "aggregate3Value", args: [[...oracleCalls, ...calls]] }); let totalValue = 0n; for (const tx of [...oracleCalls, ...calls]) { totalValue += tx.value || 0n; } const finalTx = { account: override.account || this.sdk.accountAddress, to: multicallInstance.address, data: multicallData, value: totalValue }; const response = await publicClient.call(finalTx); this.sdk.logger.info("=== response", response); const multicallResult = this.decodeResponse( multicallInstance.abi, "aggregate3Value", response.data ); const callsToDecode = multicallResult.slice(-oracleCalls.length); const decodedResult = callsToDecode.map( (result, idx) => this.decodeResponse(abi, functionNames[idx], result.returnData) ); return decodedResult; } async getMissingOracleCalls(calls, oracleCalls = [], { attemps = MAX_ERC7412_RETRIES, account, stateOverride } = {}) { const publicClient = this.sdk.getPublicClient(); const totalValue = [...oracleCalls, ...calls].reduce((acc, tx) => { return acc + (tx.value || 0n); }, 0n); this.sdk.logger.info("=== init data", { oracleCalls, calls, attemps }); const multicallInstance = await this.sdk.contracts.getMulticallInstance(); const multicallData = (0, import_viem4.encodeFunctionData)({ abi: multicallInstance.abi, functionName: "aggregate3Value", args: [[...oracleCalls, ...calls]] }); const parsedTx = { account: account || this.sdk.accountAddress, to: multicallInstance.address, data: multicallData, value: totalValue, stateOverride }; try { await publicClient.call(parsedTx); return oracleCalls; } catch (error) { const parsedError = parseError(error); this.sdk.logger.error("=== parsedError in getMissingOracleCalls", parsedError); const shouldRetry = this.shouldRetryLogic(error, attemps); console.log("=== shouldRetry", { shouldRetry, error, attemps, parsedError }); if (!shouldRetry) return oracleCalls; const data = await this.handleErc7412Error(parsedError); return await this.getMissingOracleCalls(calls, [...oracleCalls, ...data], { account, attemps: attemps - 1, stateOverride }); } } _fromCall3ToTransactionData(call) { return { to: call.target, data: call.callData, value: call?.value?.toString() ?? "0" }; } _fromTransactionDataToCall3(data, requireSuccess = true) { return { target: data.to, callData: data.data, value: BigInt(data.value || 0), requireSuccess }; } _fromCallDataToTransactionData(calls) { return { to: calls.to, data: calls.data, value: calls?.value?.toString() ?? "0" }; } _fromTransactionDataToCallData(data) { return { account: this.sdk.accountAddress, to: data.to, data: data.data, value: BigInt(data.value || 0) }; } async processTransactions(data, override) { const useOracleCall = override.useOracleCalls ?? true; const oracleCalls = useOracleCall ? await this.getMissingOracleCalls(data, void 0, { account: override.account, stateOverride: override?.stateOverride?.reduce( (acc, state) => { const includedIndex = acc.findIndex((s) => s.address === state.address); const included = override?.stateOverride?.[includedIndex]; if (!included && state.stateDiff) acc.push(state); if (included) { acc[includedIndex] = { address: state.address, stateDiff: [...state.stateDiff, ...included.stateDiff] }; } return acc; }, [] ) }) ?? void 0 : []; const txs = [ ...!override.useMultiCall ? (override.prepend || []).map((a) => this._fromTransactionDataToCall3(a, true)) : [], ...oracleCalls, ...data ]; if (!override.useMultiCall && !override.submit) return txs.map(this.sdk.utils._fromCall3ToTransactionData); const tx = await this.sdk.utils.writeErc7412({ calls: txs }, override); if (!override.submit) return [...override.prepend || [], tx]; return this.sdk.executeTransaction(this.sdk.utils._fromTransactionDataToCallData(tx)); } shouldRetryLogic(error, attemps = 0) { const parsedError = parseError(error); const isErc7412Error = this.isErc7412Error(parsedError); this.sdk.logger.error("=== parsedError in processTransactions ", { parsedError, isErc7412Error }); if (!attemps && !isErc7412Error) return false; if (!isErc7412Error) { return false; } return true; } isErc7412Error(parsedError) { return parsedError.startsWith(SIG_ORACLE_DATA_REQUIRED) || parsedError.startsWith(SIG_FEE_REQUIRED) || parsedError.startsWith(SIG_ERRORS); } }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { Utils, batchArray, convertEtherToWei, convertWeiToEther, fetcher, generateRandomAccountId, getChain, getOdosPath, getPublicRpcEndpoint, sleep }); //# sourceMappingURL=index.js.map