UNPKG

@c4tplatform/caminojs

Version:
628 lines 87.3 kB
"use strict"; /** * @packageDocumentation * @module API-EVM */ 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 __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.EVMAPI = void 0; const buffer_1 = require("buffer/"); const bn_js_1 = __importDefault(require("bn.js")); const jrpcapi_1 = require("../../common/jrpcapi"); const bintools_1 = __importDefault(require("../../utils/bintools")); const utxos_1 = require("./utxos"); const keychain_1 = require("./keychain"); const tx_1 = require("./tx"); const constants_1 = require("./constants"); const inputs_1 = require("./inputs"); const outputs_1 = require("./outputs"); const exporttx_1 = require("./exporttx"); const errors_1 = require("../../utils/errors"); const utils_1 = require("../../utils"); /** * @ignore */ const bintools = bintools_1.default.getInstance(); const serialization = utils_1.Serialization.getInstance(); /** * Class for interacting with a node's EVMAPI * * @category RPCAPIs * * @remarks This extends the [[JRPCAPI]] class. This class should not be directly called. Instead, use the [[Avalanche.addAPI]] function to register this interface with Avalanche. */ class EVMAPI extends jrpcapi_1.JRPCAPI { /** * @ignore */ _cleanAddressArray(addresses, caller) { const addrs = []; const chainid = this.getBlockchainAlias() ? this.getBlockchainAlias() : this.getBlockchainID(); if (addresses && addresses.length > 0) { addresses.forEach((address) => { if (typeof address === "string") { if (typeof this.parseAddress(address) === "undefined") { /* istanbul ignore next */ throw new errors_1.AddressError("Error - Invalid address format"); } addrs.push(address); } else { const type = "bech32"; addrs.push(serialization.bufferToType(address, type, this.core.getHRP(), chainid)); } }); } return addrs; } /** * This class should not be instantiated directly. * Instead use the [[Avalanche.addAPI]] method. * * @param core A reference to the Avalanche class * @param baseURL Defaults to the string "/ext/bc/C/avax" as the path to blockchain's baseURL * @param blockchainID The Blockchain's ID. Defaults to an empty string: "" */ constructor(core, baseURL = "/ext/bc/C/avax", blockchainID = "") { super(core, baseURL); /** * @ignore */ this.keychain = new keychain_1.KeyChain("", ""); this.blockchainID = ""; this.blockchainAlias = undefined; this.AVAXAssetID = undefined; this.txFee = undefined; /** * Gets the alias for the blockchainID if it exists, otherwise returns `undefined`. * * @returns The alias for the blockchainID */ this.getBlockchainAlias = () => { if (typeof this.blockchainAlias === "undefined") { this.blockchainAlias = this.core.getNetwork().C.alias; } return this.blockchainAlias; }; /** * Gets the blockchainID and returns it. * * @returns The blockchainID */ this.getBlockchainID = () => this.blockchainID; /** * Takes an address string and returns its {@link https://github.com/feross/buffer|Buffer} representation if valid. * * @returns A {@link https://github.com/feross/buffer|Buffer} for the address if valid, undefined if not valid. */ this.parseAddress = (addr) => { const alias = this.getBlockchainAlias(); const blockchainID = this.getBlockchainID(); return bintools.parseAddress(addr, blockchainID, alias, constants_1.EVMConstants.ADDRESSLENGTH); }; this.addressFromBuffer = (address) => { const chainID = this.getBlockchainAlias() ? this.getBlockchainAlias() : this.getBlockchainID(); const type = "bech32"; return serialization.bufferToType(address, type, this.core.getHRP(), chainID); }; /** * Retrieves an assets name and symbol. * * @param assetID Either a {@link https://github.com/feross/buffer|Buffer} or an b58 serialized string for the AssetID or its alias. * * @returns Returns a Promise Asset with keys "name", "symbol", "assetID" and "denomination". */ this.getAssetDescription = (assetID) => __awaiter(this, void 0, void 0, function* () { let asset; if (typeof assetID !== "string") { asset = bintools.cb58Encode(assetID); } else { asset = assetID; } const params = { assetID: asset }; const tmpBaseURL = this.getBaseURL(); // set base url to get asset description this.setBaseURL("/ext/bc/X"); const response = yield this.callMethod("avm.getAssetDescription", params); // set base url back what it originally was this.setBaseURL(tmpBaseURL); return { name: response.data.result.name, symbol: response.data.result.symbol, assetID: bintools.cb58Decode(response.data.result.assetID), denomination: parseInt(response.data.result.denomination, 10) }; }); /** * Fetches the AVAX AssetID and returns it in a Promise. * * @param refresh This function caches the response. Refresh = true will bust the cache. * * @returns The the provided string representing the AVAX AssetID */ this.getAVAXAssetID = (refresh = false) => __awaiter(this, void 0, void 0, function* () { if (typeof this.AVAXAssetID === "undefined" || refresh) { const asset = yield this.getAssetDescription(this.core.getPrimaryAssetAlias()); this.AVAXAssetID = asset.assetID; } return this.AVAXAssetID; }); /** * Overrides the defaults and sets the cache to a specific AVAX AssetID * * @param avaxAssetID A cb58 string or Buffer representing the AVAX AssetID * * @returns The the provided string representing the AVAX AssetID */ this.setAVAXAssetID = (avaxAssetID) => { if (typeof avaxAssetID === "string") { avaxAssetID = bintools.cb58Decode(avaxAssetID); } this.AVAXAssetID = avaxAssetID; }; /** * Gets the default tx fee for this chain. * * @returns The default tx fee as a {@link https://github.com/indutny/bn.js/|BN} */ this.getDefaultTxFee = () => { return new bn_js_1.default(this.core.getNetwork().C.txFee); }; /** * returns the amount of [assetID] for the given address in the state of the given block number. * "latest", "pending", and "accepted" meta block numbers are also allowed. * * @param hexAddress The hex representation of the address * @param blockHeight The block height * @param assetID The asset ID * * @returns Returns a Promise object containing the balance */ this.getAssetBalance = (hexAddress, blockHeight, assetID) => __awaiter(this, void 0, void 0, function* () { const params = [hexAddress, blockHeight, assetID]; const method = "eth_getAssetBalance"; const path = "ext/bc/C/rpc"; const response = yield this.callMethod(method, params, path); return response.data; }); /** * Returns the status of a provided atomic transaction ID by calling the node's `getAtomicTxStatus` method. * * @param txID The string representation of the transaction ID * * @returns Returns a Promise string containing the status retrieved from the node */ this.getAtomicTxStatus = (txID) => __awaiter(this, void 0, void 0, function* () { const params = { txID }; const response = yield this.callMethod("avax.getAtomicTxStatus", params); return response.data.result.status ? response.data.result.status : response.data.result; }); /** * Returns the transaction data of a provided transaction ID by calling the node's `getAtomicTx` method. * * @param txID The string representation of the transaction ID * * @returns Returns a Promise string containing the bytes retrieved from the node */ this.getAtomicTx = (txID) => __awaiter(this, void 0, void 0, function* () { const params = { txID }; const response = yield this.callMethod("avax.getAtomicTx", params); return response.data.result.tx; }); /** * Gets the tx fee for this chain. * * @returns The tx fee as a {@link https://github.com/indutny/bn.js/|BN} */ this.getTxFee = () => { if (typeof this.txFee === "undefined") { this.txFee = this.getDefaultTxFee(); } return this.txFee; }; /** * Send ANT (Avalanche Native Token) assets including AVAX from the C-Chain to an account on the X-Chain. * * After calling this method, you must call the X-Chain’s import method to complete the transfer. * * @param username The Keystore user that controls the X-Chain account specified in `to` * @param password The password of the Keystore user * @param to The account on the X-Chain to send the AVAX to. * @param amount Amount of asset to export as a {@link https://github.com/indutny/bn.js/|BN} * @param assetID The asset id which is being sent * * @returns String representing the transaction id */ this.export = (username, password, to, amount, assetID) => __awaiter(this, void 0, void 0, function* () { const params = { to, amount: amount.toString(10), username, password, assetID }; const response = yield this.callMethod("avax.export", params); return response.data.result.txID ? response.data.result.txID : response.data.result; }); /** * Send AVAX from the C-Chain to an account on the X-Chain. * * After calling this method, you must call the X-Chain’s importAVAX method to complete the transfer. * * @param username The Keystore user that controls the X-Chain account specified in `to` * @param password The password of the Keystore user * @param to The account on the X-Chain to send the AVAX to. * @param amount Amount of AVAX to export as a {@link https://github.com/indutny/bn.js/|BN} * * @returns String representing the transaction id */ this.exportAVAX = (username, password, to, amount) => __awaiter(this, void 0, void 0, function* () { const params = { to, amount: amount.toString(10), username, password }; const response = yield this.callMethod("avax.exportAVAX", params); return response.data.result.txID ? response.data.result.txID : response.data.result; }); /** * Retrieves the UTXOs related to the addresses provided from the node's `getUTXOs` method. * * @param addresses An array of addresses as cb58 strings or addresses as {@link https://github.com/feross/buffer|Buffer}s * @param sourceChain A string for the chain to look for the UTXO's. Default is to use this chain, but if exported UTXOs exist * from other chains, this can used to pull them instead. * @param limit Optional. Returns at most [limit] addresses. If [limit] == 0 or > [maxUTXOsToFetch], fetches up to [maxUTXOsToFetch]. * @param startIndex Optional. [StartIndex] defines where to start fetching UTXOs (for pagination.) * UTXOs fetched are from addresses equal to or greater than [StartIndex.Address] * For address [StartIndex.Address], only UTXOs with IDs greater than [StartIndex.Utxo] will be returned. */ this.getUTXOs = (addresses, sourceChain = undefined, limit = 0, startIndex = undefined, encoding = "hex") => __awaiter(this, void 0, void 0, function* () { if (typeof addresses === "string") { addresses = [addresses]; } const params = { addresses: addresses, limit, encoding }; if (typeof startIndex !== "undefined" && startIndex) { params.startIndex = startIndex; } if (typeof sourceChain !== "undefined") { params.sourceChain = sourceChain; } const response = yield this.callMethod("avax.getUTXOs", params); const utxos = new utxos_1.UTXOSet(); const data = response.data.result.utxos; if (data.length > 0 && data[0].substring(0, 2) === "0x") { const cb58Strs = []; data.forEach((str) => { cb58Strs.push(bintools.cb58Encode(buffer_1.Buffer.from(str.slice(2), "hex"))); }); utxos.addArray(cb58Strs, false); } else { utxos.addArray(data, false); } response.data.result.utxos = utxos; return response.data.result; }); /** * Send ANT (Avalanche Native Token) assets including AVAX from an account on the X-Chain to an address on the C-Chain. This transaction * must be signed with the key of the account that the asset is sent from and which pays * the transaction fee. * * @param username The Keystore user that controls the account specified in `to` * @param password The password of the Keystore user * @param to The address of the account the asset is sent to. * @param sourceChain The chainID where the funds are coming from. Ex: "X" * * @returns Promise for a string for the transaction, which should be sent to the network * by calling issueTx. */ this.import = (username, password, to, sourceChain) => __awaiter(this, void 0, void 0, function* () { const params = { to, sourceChain, username, password }; const response = yield this.callMethod("avax.import", params); return response.data.result.txID ? response.data.result.txID : response.data.result; }); /** * Send AVAX from an account on the X-Chain to an address on the C-Chain. This transaction * must be signed with the key of the account that the AVAX is sent from and which pays * the transaction fee. * * @param username The Keystore user that controls the account specified in `to` * @param password The password of the Keystore user * @param to The address of the account the AVAX is sent to. This must be the same as the to * argument in the corresponding call to the X-Chain’s exportAVAX * @param sourceChain The chainID where the funds are coming from. * * @returns Promise for a string for the transaction, which should be sent to the network * by calling issueTx. */ this.importAVAX = (username, password, to, sourceChain) => __awaiter(this, void 0, void 0, function* () { const params = { to, sourceChain, username, password }; const response = yield this.callMethod("avax.importAVAX", params); return response.data.result.txID ? response.data.result.txID : response.data.result; }); /** * Give a user control over an address by providing the private key that controls the address. * * @param username The name of the user to store the private key * @param password The password that unlocks the user * @param privateKey A string representing the private key in the vm"s format * * @returns The address for the imported private key. */ this.importKey = (username, password, privateKey) => __awaiter(this, void 0, void 0, function* () { const params = { username, password, privateKey }; const response = yield this.callMethod("avax.importKey", params); return response.data.result.address ? response.data.result.address : response.data.result; }); /** * Calls the node's issueTx method from the API and returns the resulting transaction ID as a string. * * @param tx A string, {@link https://github.com/feross/buffer|Buffer}, or [[Tx]] representing a transaction * * @returns A Promise string representing the transaction ID of the posted transaction. */ this.issueTx = (tx) => __awaiter(this, void 0, void 0, function* () { let Transaction = ""; if (typeof tx === "string") { Transaction = tx; } else if (tx instanceof buffer_1.Buffer) { const txobj = new tx_1.Tx(); txobj.fromBuffer(tx); Transaction = txobj.toStringHex(); } else if (tx instanceof tx_1.Tx) { Transaction = tx.toStringHex(); } else { /* istanbul ignore next */ throw new errors_1.TransactionError("Error - avax.issueTx: provided tx is not expected type of string, Buffer, or Tx"); } const params = { tx: Transaction.toString(), encoding: "hex" }; const response = yield this.callMethod("avax.issueTx", params); return response.data.result.txID ? response.data.result.txID : response.data.result; }); /** * Exports the private key for an address. * * @param username The name of the user with the private key * @param password The password used to decrypt the private key * @param address The address whose private key should be exported * * @returns Promise with the decrypted private key and private key hex as store in the database */ this.exportKey = (username, password, address) => __awaiter(this, void 0, void 0, function* () { const params = { username, password, address }; const response = yield this.callMethod("avax.exportKey", params); return response.data.result; }); /** * Helper function which creates an unsigned Import Tx. For more granular control, you may create your own * [[UnsignedTx]] manually (with their corresponding [[TransferableInput]]s, [[TransferableOutput]]s). * * @param utxoset A set of UTXOs that the transaction is built on * @param toAddress The address to send the funds * @param ownerAddresses The addresses being used to import * @param sourceChain The chainid for where the import is coming from * @param fromAddresses The addresses being used to send the funds from the UTXOs provided * * @returns An unsigned transaction ([[UnsignedTx]]) which contains a [[ImportTx]]. * * @remarks * This helper exists because the endpoint API should be the primary point of entry for most functionality. */ this.buildImportTx = (utxoset, toAddress, ownerAddresses, sourceChain, fee = new bn_js_1.default(0)) => __awaiter(this, void 0, void 0, function* () { let srcChain = undefined; if (typeof sourceChain === "string") { // if there is a sourceChain passed in and it's a string then save the string value and cast the original // variable from a string to a Buffer srcChain = sourceChain; sourceChain = bintools.cb58Decode(sourceChain); } else if (typeof sourceChain === "undefined" || !(sourceChain instanceof buffer_1.Buffer)) { // if there is no sourceChain passed in or the sourceChain is any data type other than a Buffer then throw an error throw new errors_1.ChainIdError("Error - EVMAPI.buildImportTx: sourceChain is undefined or invalid sourceChain type."); } var atomicUTXOs = utxoset; if (!utxoset) { const utxoResponse = yield this.getUTXOs(ownerAddresses, srcChain, 0, undefined); atomicUTXOs = utxoResponse.utxos; } const networkID = this.core.getNetworkID(); const avaxAssetID = this.core.getNetwork().X.avaxAssetID; const avaxAssetIDBuf = bintools.cb58Decode(avaxAssetID); const atomics = atomicUTXOs.getAllUTXOs(); if (atomics.length === 0) { throw new errors_1.NoAtomicUTXOsError("Error - EVMAPI.buildImportTx: no atomic utxos to import"); } const builtUnsignedTx = atomicUTXOs.buildImportTx(networkID, bintools.cb58Decode(this.blockchainID), toAddress, atomics, sourceChain, fee, avaxAssetIDBuf); return builtUnsignedTx; }); /** * Helper function which creates an unsigned Export Tx. For more granular control, you may create your own * [[UnsignedTx]] manually (with their corresponding [[TransferableInput]]s, [[TransferableOutput]]s). * * @param amount The amount being exported as a {@link https://github.com/indutny/bn.js/|BN} * @param assetID The asset id which is being sent * @param destinationChain The chainid for where the assets will be sent. * @param fromAddressesHex The addresses to send the funds (hex) * @param fromAddressesBech The addresses being used to send the funds from the UTXOs provided * @param toAddresses An array of addresses as {@link https://github.com/feross/buffer|Buffer} who recieves the AVAX * @param nonce Optional. The nonce to be used * @param locktime Optional. The locktime field created in the resulting outputs * @param toThreshold Optional. The number of signatures required to spend the funds in the resultant UTXO * @param fee Optional. The the fee for this transaction * * @returns An unsigned transaction ([[UnsignedTx]]) which contains an [[ExportTx]]. */ this.buildExportTx = (amount, assetID, destinationChain, fromAddressHex, fromAddressBech, toAddresses, nonce = 0, locktime = new bn_js_1.default(0), toThreshold = 1, fee = new bn_js_1.default(0)) => __awaiter(this, void 0, void 0, function* () { const prefixes = {}; toAddresses.map((address) => { prefixes[address.split("-")[0]] = true; }); if (Object.keys(prefixes).length !== 1) { throw new errors_1.AddressError("Error - EVMAPI.buildExportTx: To addresses must have the same chainID prefix."); } if (typeof destinationChain === "undefined") { throw new errors_1.ChainIdError("Error - EVMAPI.buildExportTx: Destination ChainID is undefined."); } else if (typeof destinationChain === "string") { destinationChain = bintools.cb58Decode(destinationChain); } else if (!(destinationChain instanceof buffer_1.Buffer)) { throw new errors_1.ChainIdError("Error - EVMAPI.buildExportTx: Invalid destinationChain type"); } if (destinationChain.length !== 32) { throw new errors_1.ChainIdError("Error - EVMAPI.buildExportTx: Destination ChainID must be 32 bytes in length."); } const assetDescription = yield this.getAssetDescription(this.core.getPrimaryAssetAlias()); let evmInputs = []; if (bintools.cb58Encode(assetDescription.assetID) === assetID) { const evmInput = new inputs_1.EVMInput(fromAddressHex, amount.add(fee), assetID, nonce); evmInput.addSignatureIdx(0, bintools.stringToAddress(fromAddressBech)); evmInputs.push(evmInput); } else { // if asset id isn't AVAX asset id then create 2 inputs // first input will be AVAX and will be for the amount of the fee // second input will be the ANT const evmAVAXInput = new inputs_1.EVMInput(fromAddressHex, fee, assetDescription.assetID, nonce); evmAVAXInput.addSignatureIdx(0, bintools.stringToAddress(fromAddressBech)); evmInputs.push(evmAVAXInput); const evmANTInput = new inputs_1.EVMInput(fromAddressHex, amount, assetID, nonce); evmANTInput.addSignatureIdx(0, bintools.stringToAddress(fromAddressBech)); evmInputs.push(evmANTInput); } const to = []; toAddresses.map((address) => { to.push(bintools.stringToAddress(address)); }); let exportedOuts = []; const secpTransferOutput = new outputs_1.SECPTransferOutput(amount, to, locktime, toThreshold); const transferableOutput = new outputs_1.TransferableOutput(bintools.cb58Decode(assetID), secpTransferOutput); exportedOuts.push(transferableOutput); // lexicographically sort ins and outs evmInputs = evmInputs.sort(inputs_1.EVMInput.comparator()); exportedOuts = exportedOuts.sort(outputs_1.TransferableOutput.comparator()); const exportTx = new exporttx_1.ExportTx(this.core.getNetworkID(), bintools.cb58Decode(this.blockchainID), destinationChain, evmInputs, exportedOuts); const unsignedTx = new tx_1.UnsignedTx(exportTx); return unsignedTx; }); /** * Gets a reference to the keychain for this class. * * @returns The instance of [[KeyChain]] for this class */ this.keyChain = () => this.keychain; /** * * @returns new instance of [[KeyChain]] */ this.newKeyChain = () => { // warning, overwrites the old keychain const alias = this.getBlockchainAlias(); if (alias) { this.keychain = new keychain_1.KeyChain(this.core.getHRP(), alias); } else { this.keychain = new keychain_1.KeyChain(this.core.getHRP(), this.blockchainID); } return this.keychain; }; /** * @returns a Promise string containing the base fee for the next block. */ this.getBaseFee = () => __awaiter(this, void 0, void 0, function* () { const params = []; const method = "eth_baseFee"; const path = "ext/bc/C/rpc"; const response = yield this.callMethod(method, params, path); return response.data.result; }); /** * returns the priority fee needed to be included in a block. * * @returns Returns a Promise string containing the priority fee needed to be included in a block. */ this.getMaxPriorityFeePerGas = () => __awaiter(this, void 0, void 0, function* () { const params = []; const method = "eth_maxPriorityFeePerGas"; const path = "ext/bc/C/rpc"; const response = yield this.callMethod(method, params, path); return response.data.result; }); this.blockchainID = core.getNetwork().C.blockchainID; if (blockchainID !== "" && blockchainID !== this.blockchainID) { this.keychain = new keychain_1.KeyChain(this.core.getHRP(), blockchainID); this.blockchainID = blockchainID; } else { this.keychain = new keychain_1.KeyChain(this.core.getHRP(), core.getNetwork().C.alias); } } } exports.EVMAPI = EVMAPI; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBpLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2FwaXMvZXZtL2FwaS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7OztHQUdHOzs7Ozs7Ozs7Ozs7Ozs7QUFFSCxvQ0FBZ0M7QUFDaEMsa0RBQXNCO0FBRXRCLGtEQUE4QztBQUU5QyxvRUFBMkM7QUFDM0MsbUNBQXVDO0FBQ3ZDLHlDQUFxQztBQUNyQyw2QkFBcUM7QUFDckMsMkNBQTBDO0FBTzFDLHFDQUFtQztBQUNuQyx1Q0FBa0U7QUFDbEUseUNBQXFDO0FBQ3JDLCtDQUsyQjtBQUMzQix1Q0FBMkQ7QUFjM0Q7O0dBRUc7QUFDSCxNQUFNLFFBQVEsR0FBYSxrQkFBUSxDQUFDLFdBQVcsRUFBRSxDQUFBO0FBQ2pELE1BQU0sYUFBYSxHQUFrQixxQkFBYSxDQUFDLFdBQVcsRUFBRSxDQUFBO0FBRWhFOzs7Ozs7R0FNRztBQUNILE1BQWEsTUFBTyxTQUFRLGlCQUFPO0lBbXRCakM7O09BRUc7SUFDTyxrQkFBa0IsQ0FDMUIsU0FBOEIsRUFDOUIsTUFBYztRQUVkLE1BQU0sS0FBSyxHQUFhLEVBQUUsQ0FBQTtRQUMxQixNQUFNLE9BQU8sR0FBVyxJQUFJLENBQUMsa0JBQWtCLEVBQUU7WUFDL0MsQ0FBQyxDQUFDLElBQUksQ0FBQyxrQkFBa0IsRUFBRTtZQUMzQixDQUFDLENBQUMsSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFBO1FBQzFCLElBQUksU0FBUyxJQUFJLFNBQVMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFO1lBQ3JDLFNBQVMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxPQUF3QixFQUFFLEVBQUU7Z0JBQzdDLElBQUksT0FBTyxPQUFPLEtBQUssUUFBUSxFQUFFO29CQUMvQixJQUFJLE9BQU8sSUFBSSxDQUFDLFlBQVksQ0FBQyxPQUFpQixDQUFDLEtBQUssV0FBVyxFQUFFO3dCQUMvRCwwQkFBMEI7d0JBQzFCLE1BQU0sSUFBSSxxQkFBWSxDQUFDLGdDQUFn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LENBQUE7U0FDRjtJQUNILENBQUM7Q0FrQ0Y7QUFqekJELHdCQWl6QkMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBwYWNrYWdlRG9jdW1lbnRhdGlvblxuICogQG1vZHVsZSBBUEktRVZNXG4gKi9cblxuaW1wb3J0IHsgQnVmZmVyIH0gZnJvbSBcImJ1ZmZlci9cIlxuaW1wb3J0IEJOIGZyb20gXCJibi5qc1wiXG5pbXBvcnQgQXZhbGFuY2hlQ29yZSBmcm9tIFwiLi4vLi4vY2FtaW5vXCJcbmltcG9ydCB7IEpSUENBUEkgfSBmcm9tIFwiLi4vLi4vY29tbW9uL2pycGNhcGlcIlxuaW1wb3J0IHsgUmVxdWVzdFJlc3BvbnNlRGF0YSB9IGZyb20gXCIuLi8uLi9jb21tb24vYXBpYmFzZVwiXG5pbXBvcnQgQmluVG9vbHMgZnJvbSBcIi4uLy4uL3V0aWxzL2JpbnRvb2xzXCJcbmltcG9ydCB7IFVUWE9TZXQsIFVUWE8gfSBmcm9tIFwiLi91dHhvc1wiXG5pbXBvcnQgeyBLZXlDaGFpbiB9IGZyb20gXCIuL2tleWNoYWluXCJcbmltcG9