diff --git a/README.md b/README.md index 34217be..ff21c27 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ OVAL_ADDRESS=0x420 # (Only if not using OVAL_CONFIGS) REFUND_ADDRESS=0x42069 # (Only if not using OVAL_CONFIGS) The refund address you want to send the OEV kickback to. REFUND_PERCENT=0.5 # (Only if not using OVAL_CONFIGS) The percentage of the OEV kickback to send to the refund address. SENDER_PRIVATE_KEY= # (Only if not using OVAL_CONFIGS) Private key of the actor authorized to call unlockLatestValue on the Oval. +GCKMS_CONFIG= # JSON string that specifies the GCKMS configuration for retrieving unlocker keys. (Optional) AUTH_PRIVATE_KEY= # Root private key for deriving searcher-specific keys for signing bundles. PROVIDER_URL= # Ethereum mainnet/goerli RPC provider URL. @@ -47,10 +48,12 @@ CHAIN_ID= # Chain ID of the Ethereum network `OVAL_CONFIGS` is a JSON string that maps Oval contract addresses to their specific configurations. Each entry in this JSON object should have the following format: + ```json { "": { - "unlockerKey": "", + "unlockerKey": "", // Optional: Use either this or gckmsKeyId, not both. + "gckmsKeyId": "", // Optional: Use either this or unlockerKey, not both. "refundAddress": "", "refundPercent": } @@ -59,6 +62,7 @@ CHAIN_ID= # Chain ID of the Ethereum network - `Oval_Contract_Address`: The Ethereum address of the Oval instance. - `Unlocker_Private_Key`: The private key of the wallet permitted to unlock prices in the specified Oval contract. +- `GCKMS_Key_ID`: The GCKMS key ID of the wallet permitted to unlock prices in the specified Oval contract. - `Refund_Address`: The Ethereum address where refunds will be sent. - `Refund_Percentage`: The percentage of the OEV kickback to send to the refund address. diff --git a/package.json b/package.json index bb1c29a..89a5614 100644 --- a/package.json +++ b/package.json @@ -5,10 +5,13 @@ "author": "", "dependencies": { "@flashbots/mev-share-client": "^0.7.12", + "@google-cloud/kms": "^4.5.0", + "@google-cloud/storage": "^7.11.2", "@types/axios": "^0.14.0", "@types/body-parser": "^1.19.4", "@types/express": "^4.17.20", "@types/morgan": "^1.9.7", + "@types/uuid": "^9.0.8", "@uma/logger": "^1.1.0", "axios": "^1.5.1", "body-parser": "^1.20.2", @@ -20,8 +23,7 @@ "nodemon": "^3.0.1", "prettier": "^3.0.0", "ts-node": "^10.9.2", - "typescript": "^5.2.2", - "@types/uuid": "^9.0.8" + "typescript": "^5.2.2" }, "devDependencies": { "@types/eventsource": "^1.1.11", diff --git a/src/index.ts b/src/index.ts index 764eca6..8111971 100644 --- a/src/index.ts +++ b/src/index.ts @@ -20,6 +20,7 @@ import { FLASHBOTS_SIGNATURE_HEADER, Logger, OVAL_ADDRESSES_HEADER, + WalletManager, Refund, adjustRefundPercent, createUnlockLatestValueBundle, @@ -46,6 +47,10 @@ app.use((req, res, next) => { const provider = getProvider(); const { ovalConfigs } = env; +// Initialize unlocker wallets for each Oval instance. +const keyManager = WalletManager.getInstance(); +keyManager.initialize(ovalConfigs); + // Start restful API server to listen for root inbound post requests. app.post("/", async (req, res, next) => { try { @@ -121,7 +126,8 @@ app.post("/", async (req, res, next) => { }, ]; - return sendBundle(req, res, mevshare, targetBlock, body.id, bundle, refunds); + await sendBundle(req, res, mevshare, targetBlock, body.id, bundle, refunds); + return; } else { // If configured, simulate the original bundle to check if it reverts without the unlock. if (env.passThroughNonReverting) { @@ -176,7 +182,8 @@ app.post("/", async (req, res, next) => { } // Exit the function here to prevent the request from being forwarded to the FORWARD_URL. - return sendBundle(req, res, mevshare, targetBlock, body.id, bundle, refunds); + await sendBundle(req, res, mevshare, targetBlock, body.id, bundle, refunds); + return; } else if (verifiedSignatureSearcherPkey && body.method == "eth_callBundle") { if (!isEthCallBundleParams(body.params)) { Logger.info(req.transactionId, "Received unsupported eth_callBundle request!", { body }); diff --git a/src/lib/bundleUtils.ts b/src/lib/bundleUtils.ts index 90450ae..6000af7 100644 --- a/src/lib/bundleUtils.ts +++ b/src/lib/bundleUtils.ts @@ -1,7 +1,7 @@ import { Interface, Transaction, TransactionRequest, Wallet } from "ethers"; import express from "express"; import { FlashbotsBundleProvider } from "flashbots-ethers-v6-provider-bundle"; -import { getBaseFee, getMaxBlockByChainId, getProvider, initWallets } from "./helpers"; +import { WalletManager, getBaseFee, getMaxBlockByChainId, getProvider } from "./helpers"; import MevShareClient, { BundleParams } from "@flashbots/mev-share-client"; import { JSONRPCID, createJSONRPCSuccessResponse } from "json-rpc-2.0"; @@ -55,11 +55,11 @@ export const prepareUnlockTransaction = async ( simulate = true, ) => { const provider = getProvider(); - const unlockerWallets = initWallets(provider); + const unlockerWallet = WalletManager.getInstance().getWallet(ovalAddress, provider); const [baseFee, network] = await Promise.all([getBaseFee(provider, req), provider.getNetwork()]); const data = ovalInterface.encodeFunctionData("unlockLatestValue"); const { unlockTxHash, signedUnlockTx } = await createUnlockLatestValueTx( - unlockerWallets[ovalAddress], + unlockerWallet, baseFee, data, network.chainId, diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 6c9845a..d45b6d7 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -1,6 +1,7 @@ export const fallback = { chainId: 1, port: 3000, + gckmsConfig: '{"projectId":"keys-oval-8149", "locationId":"us-east1", "keyRingId":"keyring-oval", "cryptoKeyId":"", "ciphertextBucket":"bucket-keyring-oval", "ciphertextFilename":""}', forwardUrl: "https://relay.flashbots.net", refundPercent: "90", builders: [ diff --git a/src/lib/env.ts b/src/lib/env.ts index ce8721b..cd76060 100644 --- a/src/lib/env.ts +++ b/src/lib/env.ts @@ -44,6 +44,7 @@ type EnvironmentVariables = { passThroughNonReverting: boolean; maxOvalHeaderAddresses: number; flashbotsOrigin: string | undefined; + gckmsConfig: string; chainIdBlockOffsets: { [key: number]: number; }; @@ -51,6 +52,7 @@ type EnvironmentVariables = { export const env: EnvironmentVariables = { port: getInt(getEnvVar("PORT", fallback.port.toString())), + gckmsConfig: getEnvVar("GCKMS_CONFIG", fallback.gckmsConfig), authKey: getPrivateKey(getEnvVar("AUTH_PRIVATE_KEY")), chainId, providerUrl: getEnvVar("PROVIDER_URL"), diff --git a/src/lib/gckms.ts b/src/lib/gckms.ts new file mode 100644 index 0000000..be4f222 --- /dev/null +++ b/src/lib/gckms.ts @@ -0,0 +1,48 @@ +import kms from "@google-cloud/kms"; +import { Storage } from "@google-cloud/storage"; + +export interface KeyConfig { + projectId: string; + locationId: string; + keyRingId: string; + cryptoKeyId: string; + ciphertextBucket: string; + ciphertextFilename: string; +} + +const { GCP_STORAGE_CONFIG } = process.env; + +// Allows the environment to customize the config that's used to interact with google cloud storage. +// Relevant options can be found here: https://googleapis.dev/nodejs/storage/latest/global.html#StorageOptions. +// Specific fields of interest: +// - timeout: allows the env to set the timeout for all http requests. +// - retryOptions: object that allows the caller to specify how the library retries. +const storageConfig = GCP_STORAGE_CONFIG ? JSON.parse(GCP_STORAGE_CONFIG) : undefined; + +// This function takes an array of GCKMS configs that are shaped as follows: +// { +// projectId: "project-name", +// locationId: "asia-east2", +// keyRingId: "Keyring_Test", +// cryptoKeyId: "keyname", +// ciphertextBucket: "cipher_bucket", +// ciphertextFilename: "ciphertext_fname.enc", +// } +// +// It returns a private key that can be used to send transactions. +export async function retrieveGckmsKey(gckmsConfig: KeyConfig): Promise { + + const storage = new Storage(storageConfig); + const keyMaterialBucket = storage.bucket(gckmsConfig.ciphertextBucket); + const ciphertextFile = keyMaterialBucket.file(gckmsConfig.ciphertextFilename); + + const contentsBuffer = (await ciphertextFile.download())[0]; + const ciphertext = contentsBuffer.toString("base64"); + + // Send the request to decrypt the downloaded file. + const client = new kms.KeyManagementServiceClient(); + const name = client.cryptoKeyPath(gckmsConfig.projectId, gckmsConfig.locationId, gckmsConfig.keyRingId, gckmsConfig.cryptoKeyId); + const [result] = await client.decrypt({ name, ciphertext }); + if (!(result.plaintext instanceof Uint8Array)) throw new Error("result.plaintext wrong type"); + return "0x" + Buffer.from(result.plaintext).toString().trim(); +} \ No newline at end of file diff --git a/src/lib/helpers.ts b/src/lib/helpers.ts index 299c129..7283ea8 100644 --- a/src/lib/helpers.ts +++ b/src/lib/helpers.ts @@ -17,23 +17,13 @@ import { flashbotsSupportedNetworks, supportedNetworks } from "./constants"; import { env } from "./env"; import { Logger } from "./logging"; import { OvalAddressConfigList, OvalConfig, OvalConfigs } from "./types"; +import { retrieveGckmsKey } from "./gckms"; export function getProvider() { const network = new Network(supportedNetworks[env.chainId], env.chainId); return new JsonRpcProvider(env.providerUrl, network); } -// Initialize unlocker wallets for each Oval instance. -export function initWallets(provider: JsonRpcProvider) { - return Object.entries(env.ovalConfigs).reduce( - (wallets, [address, config]) => { - wallets[address] = new Wallet(config.unlockerKey).connect(provider); - return wallets; - }, - {} as Record, - ); -} - export async function initClients(provider: JsonRpcProvider, searcherPublicKey: string) { // Derive a private key from the searcher's public key and the unlocker's private key. // This approach ensures that each searcher maintains an independent reputation within the Flashbots network, @@ -186,10 +176,14 @@ function isOvalConfig(input: unknown): input is OvalConfig { typeof input === "object" && input !== null && !Array.isArray(input) && - "unlockerKey" in input && - typeof input["unlockerKey"] === "string" && - ((!input["unlockerKey"].startsWith("0x") && isHexString("0x" + input["unlockerKey"], 32)) || - isHexString(input["unlockerKey"], 32)) && + ( + ("unlockerKey" in input && typeof input["unlockerKey"] === "string" && + ((!input["unlockerKey"].startsWith("0x") && isHexString("0x" + input["unlockerKey"], 32)) || + isHexString(input["unlockerKey"], 32)) && + !("gckmsKeyId" in input)) || + ("gckmsKeyId" in input && typeof input["gckmsKeyId"] === "string" && + !("unlockerKey" in input)) + ) && "refundAddress" in input && typeof input["refundAddress"] === "string" && isAddress(input["refundAddress"]) && @@ -219,6 +213,7 @@ const normaliseOvalConfigs = (config: OvalConfigs): OvalConfigs => { for (const [address, ovalConfig] of Object.entries(config)) { normalised[getAddress(address)] = { unlockerKey: ovalConfig.unlockerKey, + gckmsKeyId: ovalConfig.gckmsKeyId, refundAddress: getAddress(ovalConfig.refundAddress), refundPercent: ovalConfig.refundPercent, }; @@ -315,3 +310,40 @@ export function getMaxBlockByChainId(chainId: number, targetBlock: number) { // In mainnet this is always the targetBlock, but in Goerli we add 24 blocks to the targetBlock. return targetBlock + env.chainIdBlockOffsets[chainId]; } +export class WalletManager { + private static instance: WalletManager; + private wallets: Record = {}; + + private constructor() { } + + public static getInstance(): WalletManager { + if (!WalletManager.instance) { + WalletManager.instance = new WalletManager(); + } + return WalletManager.instance; + } + + public async initialize(ovalConfigs: OvalConfigs) { + // Oval Config addresses are already checksummed. + for (const [address, config] of Object.entries(ovalConfigs)) { + if (config.unlockerKey) { + this.wallets[address] = new Wallet(config.unlockerKey); + } else if (config.gckmsKeyId) { + const gckmsKey = await retrieveGckmsKey({ + ...JSON.parse(env.gckmsConfig), + cryptoKeyId: config.gckmsKeyId, + ciphertextFilename: `${config.gckmsKeyId}.enc`, + }); + this.wallets[address] = new Wallet(gckmsKey); + } + } + } + + public getWallet(address: string, provider: JsonRpcProvider): Wallet { + const checkSummedAddress = getAddress(address); + if (!this.wallets[checkSummedAddress]) { + throw new Error(`No unlocker key or GCKMS key ID found for Oval address ${address}`); + } + return this.wallets[checkSummedAddress].connect(provider); + } +} \ No newline at end of file diff --git a/src/lib/types.ts b/src/lib/types.ts index 7692100..fb62a58 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -1,5 +1,6 @@ export interface OvalConfig { - unlockerKey: string; + unlockerKey?: string; + gckmsKeyId?: string; refundAddress: string; refundPercent: number; } diff --git a/yarn.lock b/yarn.lock index da63216..8ada48b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -351,6 +351,13 @@ retry-request "^4.2.2" teeny-request "^7.0.0" +"@google-cloud/kms@^4.5.0": + version "4.5.0" + resolved "https://registry.yarnpkg.com/@google-cloud/kms/-/kms-4.5.0.tgz#c3336a13e54559cbe40e42ab803cc6cefc2aa3c7" + integrity sha512-i2vC0DI7bdfEhQszqASTw0KVvbB7HsO2CwTBod423NawAu7FWi+gVVa7NLfXVNGJaZZayFfci2Hu+om/HmyEjQ== + dependencies: + google-gax "^4.0.3" + "@google-cloud/logging-winston@^4.1.1": version "4.2.4" resolved "https://registry.yarnpkg.com/@google-cloud/logging-winston/-/logging-winston-4.2.4.tgz#dd7a2eed48262df993c0d9b231e893c04ef571e4" @@ -390,16 +397,55 @@ arrify "^2.0.0" extend "^3.0.2" +"@google-cloud/paginator@^5.0.0": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@google-cloud/paginator/-/paginator-5.0.2.tgz#86ad773266ce9f3b82955a8f75e22cd012ccc889" + integrity sha512-DJS3s0OVH4zFDB1PzjxAsHqJT6sKVbRwwML0ZBP9PbU7Yebtu/7SWMRzvO2J3nUi9pRNITCfu4LJeooM2w4pjg== + dependencies: + arrify "^2.0.0" + extend "^3.0.2" + "@google-cloud/projectify@^2.0.0": version "2.1.1" resolved "https://registry.yarnpkg.com/@google-cloud/projectify/-/projectify-2.1.1.tgz#ae6af4fee02d78d044ae434699a630f8df0084ef" integrity sha512-+rssMZHnlh0twl122gXY4/aCrk0G1acBqkHFfYddtsqpYXGxA29nj9V5V9SfC+GyOG00l650f6lG9KL+EpFEWQ== +"@google-cloud/projectify@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@google-cloud/projectify/-/projectify-4.0.0.tgz#d600e0433daf51b88c1fa95ac7f02e38e80a07be" + integrity sha512-MmaX6HeSvyPbWGwFq7mXdo0uQZLGBYCwziiLIGq5JVX+/bdI3SAq6bP98trV5eTWfLuvsMcIC1YJOF2vfteLFA== + "@google-cloud/promisify@^2.0.0": version "2.0.4" resolved "https://registry.yarnpkg.com/@google-cloud/promisify/-/promisify-2.0.4.tgz#9d8705ecb2baa41b6b2673f3a8e9b7b7e1abc52a" integrity sha512-j8yRSSqswWi1QqUGKVEKOG03Q7qOoZP6/h2zN2YO+F5h2+DHU0bSrHCK9Y7lo2DI9fBd8qGAw795sf+3Jva4yA== +"@google-cloud/promisify@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@google-cloud/promisify/-/promisify-4.0.0.tgz#a906e533ebdd0f754dca2509933334ce58b8c8b1" + integrity sha512-Orxzlfb9c67A15cq2JQEyVc7wEsmFBmHjZWZYQMUyJ1qivXyMwdyNOs9odi79hze+2zqdTtu1E19IM/FtqZ10g== + +"@google-cloud/storage@^7.11.2": + version "7.11.2" + resolved "https://registry.yarnpkg.com/@google-cloud/storage/-/storage-7.11.2.tgz#a8942d9a4a75634186d262b82c5b41e90649f11c" + integrity sha512-jJOrKyOdujfrSF8EJODW9yY6hqO4jSTk6eVITEj2gsD43BSXuDlnMlLOaBUQhXL29VGnSkxDgYl5tlFhA6LKSA== + dependencies: + "@google-cloud/paginator" "^5.0.0" + "@google-cloud/projectify" "^4.0.0" + "@google-cloud/promisify" "^4.0.0" + abort-controller "^3.0.0" + async-retry "^1.3.3" + duplexify "^4.1.3" + fast-xml-parser "^4.3.0" + gaxios "^6.0.2" + google-auth-library "^9.6.3" + html-entities "^2.5.2" + mime "^3.0.0" + p-limit "^3.0.1" + retry-request "^7.0.0" + teeny-request "^9.0.0" + uuid "^8.0.0" + "@google-cloud/trace-agent@^5.1.6": version "5.1.6" resolved "https://registry.yarnpkg.com/@google-cloud/trace-agent/-/trace-agent-5.1.6.tgz#503ed66883c2be376d8a5d87a88fdd2008f40c44" @@ -422,6 +468,14 @@ source-map-support "^0.5.16" uuid "^8.0.0" +"@grpc/grpc-js@^1.10.9": + version "1.10.10" + resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.10.10.tgz#476d315feeb9dbb0f2d6560008c92688c30f13e0" + integrity sha512-HPa/K5NX6ahMoeBv15njAc/sfF4/jmiXLar9UlC2UfHFKZzsCVLc3wbe7+7qua7w9VPh2/L6EBxyAV7/E8Wftg== + dependencies: + "@grpc/proto-loader" "^0.7.13" + "@js-sdsl/ordered-map" "^4.4.2" + "@grpc/grpc-js@~1.6.0": version "1.6.12" resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.6.12.tgz#20f710d8a8c5c396b2ae9530ba6c06b984614fdf" @@ -451,6 +505,16 @@ protobufjs "^7.2.4" yargs "^17.7.2" +"@grpc/proto-loader@^0.7.13": + version "0.7.13" + resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.7.13.tgz#f6a44b2b7c9f7b609f5748c6eac2d420e37670cf" + integrity sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw== + dependencies: + lodash.camelcase "^4.3.0" + long "^5.0.0" + protobufjs "^7.2.5" + yargs "^17.7.2" + "@isaacs/string-locale-compare@^1.0.1", "@isaacs/string-locale-compare@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@isaacs/string-locale-compare/-/string-locale-compare-1.1.0.tgz#291c227e93fd407a96ecd59879a35809120e432b" @@ -474,6 +538,11 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" +"@js-sdsl/ordered-map@^4.4.2": + version "4.4.2" + resolved "https://registry.yarnpkg.com/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz#9299f82874bab9e4c7f9c48d865becbfe8d6907c" + integrity sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw== + "@noble/curves@1.1.0", "@noble/curves@~1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.1.0.tgz#f13fc667c89184bc04cccb9b11e8e7bae27d8c3d" @@ -873,6 +942,11 @@ "@types/node" "*" "@types/responselike" "^1.0.0" +"@types/caseless@*": + version "0.12.5" + resolved "https://registry.yarnpkg.com/@types/caseless/-/caseless-0.12.5.tgz#db9468cb1b1b5a925b8f34822f1669df0c5472f5" + integrity sha512-hWtVTC2q7hc7xZ/RLbxapMvDMgUnDvKvMOpKal4DrMyfGBUfB1oKaZlIRr6mJL+If3bAP6sV/QneGzF6tJjZDg== + "@types/connect@*": version "3.4.37" resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.37.tgz#c66a96689fd3127c8772eb3e9e5c6028ec1a9af5" @@ -995,6 +1069,16 @@ resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.6.tgz#7cb33992049fd7340d5b10c0098e104184dfcd2a" integrity sha512-+0autS93xyXizIYiyL02FCY8N+KkKPhILhcUSA276HxzreZ16kl+cmwvV2qAM/PuCCwPXzOXOWhiPcw20uSFcA== +"@types/request@^2.48.8": + version "2.48.12" + resolved "https://registry.yarnpkg.com/@types/request/-/request-2.48.12.tgz#0f590f615a10f87da18e9790ac94c29ec4c5ef30" + integrity sha512-G3sY+NpsA9jnwm0ixhAFQSJ3Q9JkpLZpJbI3GMv0mIAT0y3mRabYeINzal5WOChIiaTEGQYlHOKgkaM9EisWHw== + dependencies: + "@types/caseless" "*" + "@types/node" "*" + "@types/tough-cookie" "*" + form-data "^2.5.0" + "@types/responselike@^1.0.0": version "1.0.3" resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.3.tgz#cc29706f0a397cfe6df89debfe4bf5cea159db50" @@ -1031,6 +1115,11 @@ "@types/mime" "*" "@types/node" "*" +"@types/tough-cookie@*": + version "4.0.5" + resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.5.tgz#cb6e2a691b70cb177c6e3ae9c1d2e8b2ea8cd304" + integrity sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA== + "@types/triple-beam@^1.3.2": version "1.3.5" resolved "https://registry.yarnpkg.com/@types/triple-beam/-/triple-beam-1.3.5.tgz#74fef9ffbaa198eb8b588be029f38b00299caa2c" @@ -1209,6 +1298,13 @@ agent-base@6, agent-base@^6.0.2: dependencies: debug "4" +agent-base@^7.0.2: + version "7.1.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.1.tgz#bdbded7dfb096b751a2a087eeeb9664725b2e317" + integrity sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA== + dependencies: + debug "^4.3.4" + agentkeepalive@^4.1.3: version "4.5.0" resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.5.0.tgz#2673ad1389b3c418c5a20c5d7364f93ca04be923" @@ -1362,6 +1458,13 @@ async-mutex@^0.4.0: dependencies: tslib "^2.4.0" +async-retry@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/async-retry/-/async-retry-1.3.3.tgz#0e7f36c04d8478e7a58bdbed80cedf977785f280" + integrity sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw== + dependencies: + retry "0.13.1" + async@^3.2.3: version "3.2.5" resolved "https://registry.yarnpkg.com/async/-/async-3.2.5.tgz#ebd52a8fdaf7a2289a24df399f8d8485c8a46b66" @@ -2190,6 +2293,16 @@ duplexify@^4.0.0, duplexify@^4.1.1: readable-stream "^3.1.1" stream-shift "^1.0.0" +duplexify@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-4.1.3.tgz#a07e1c0d0a2c001158563d32592ba58bddb0236f" + integrity sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA== + dependencies: + end-of-stream "^1.4.1" + inherits "^2.0.3" + readable-stream "^3.1.1" + stream-shift "^1.0.2" + ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" @@ -2564,6 +2677,13 @@ fast-text-encoding@^1.0.0, fast-text-encoding@^1.0.3: resolved "https://registry.yarnpkg.com/fast-text-encoding/-/fast-text-encoding-1.0.6.tgz#0aa25f7f638222e3396d72bf936afcf1d42d6867" integrity sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w== +fast-xml-parser@^4.3.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.4.0.tgz#341cc98de71e9ba9e651a67f41f1752d1441a501" + integrity sha512-kLY3jFlwIYwBNDojclKsNAC12sfD6NwW74QB2CoNGPvtVxjliYehVunB3HYyNi+n4Tt1dAcgwYvmKF/Z18flqg== + dependencies: + strnum "^1.0.5" + fastest-levenshtein@^1.0.12: version "1.0.16" resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5" @@ -2633,6 +2753,15 @@ form-data-encoder@1.7.1: resolved "https://registry.yarnpkg.com/form-data-encoder/-/form-data-encoder-1.7.1.tgz#ac80660e4f87ee0d3d3c3638b7da8278ddb8ec96" integrity sha512-EFRDrsMm/kyqbTQocNvRXMLjc7Es2Vk+IQFx/YW7hkUH1eBl4J1fqiP34l74Yt0pFLCNpc06fkbVk00008mzjg== +form-data@^2.5.0: + version "2.5.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.5.1.tgz#f2cbec57b5e59e23716e128fe44d4e5dd23895f4" + integrity sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + form-data@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" @@ -2744,6 +2873,17 @@ gaxios@^4.0.0: is-stream "^2.0.0" node-fetch "^2.6.7" +gaxios@^6.0.0, gaxios@^6.0.2, gaxios@^6.1.1: + version "6.7.0" + resolved "https://registry.yarnpkg.com/gaxios/-/gaxios-6.7.0.tgz#37b7c5961cb67d8d4b0ae8110dcd83cc6791eb6d" + integrity sha512-DSrkyMTfAnAm4ks9Go20QGOcXEyW/NmZhvTYBU2rb4afBB393WIMQPWPEDMl/k8xqiNN9HYq2zao3oWXsdl2Tg== + dependencies: + extend "^3.0.2" + https-proxy-agent "^7.0.1" + is-stream "^2.0.0" + node-fetch "^2.6.9" + uuid "^10.0.0" + gcp-metadata@^4.0.0, gcp-metadata@^4.2.0: version "4.3.1" resolved "https://registry.yarnpkg.com/gcp-metadata/-/gcp-metadata-4.3.1.tgz#fb205fe6a90fef2fd9c85e6ba06e5559ee1eefa9" @@ -2752,6 +2892,14 @@ gcp-metadata@^4.0.0, gcp-metadata@^4.2.0: gaxios "^4.0.0" json-bigint "^1.0.0" +gcp-metadata@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/gcp-metadata/-/gcp-metadata-6.1.0.tgz#9b0dd2b2445258e7597f2024332d20611cbd6b8c" + integrity sha512-Jh/AIwwgaxan+7ZUUmRLCjtchyDiqh4KjBJ5tW3plBZb5iL/BPcso8A5DlzeD9qlw0duCamnNdpFjxwaT0KyKg== + dependencies: + gaxios "^6.0.0" + json-bigint "^1.0.0" + get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" @@ -2850,6 +2998,18 @@ google-auth-library@^7.0.0, google-auth-library@^7.14.0: jws "^4.0.0" lru-cache "^6.0.0" +google-auth-library@^9.3.0, google-auth-library@^9.6.3: + version "9.11.0" + resolved "https://registry.yarnpkg.com/google-auth-library/-/google-auth-library-9.11.0.tgz#bd6da364bcde4e0cc4ed70a0e0df5112b6a671dd" + integrity sha512-epX3ww/mNnhl6tL45EQ/oixsY8JLEgUFoT4A5E/5iAR4esld9Kqv6IJGk7EmGuOgDvaarwF95hU2+v7Irql9lw== + dependencies: + base64-js "^1.3.0" + ecdsa-sig-formatter "^1.0.11" + gaxios "^6.1.1" + gcp-metadata "^6.1.0" + gtoken "^7.0.0" + jws "^4.0.0" + google-gax@^2.24.1: version "2.30.5" resolved "https://registry.yarnpkg.com/google-gax/-/google-gax-2.30.5.tgz#e836f984f3228900a8336f608c83d75f9cb73eff" @@ -2869,6 +3029,24 @@ google-gax@^2.24.1: protobufjs "6.11.3" retry-request "^4.0.0" +google-gax@^4.0.3: + version "4.3.7" + resolved "https://registry.yarnpkg.com/google-gax/-/google-gax-4.3.7.tgz#f1870902d09c54c5d1735ef1ee7903d4458d6a49" + integrity sha512-3bnD8RASQyaxOYTdWLgwpQco/aytTxFavoI/UN5QN5txDLp8QRrBHNtCUJ5+Ago+551GD92jG8jJduwvmaneUw== + dependencies: + "@grpc/grpc-js" "^1.10.9" + "@grpc/proto-loader" "^0.7.13" + "@types/long" "^4.0.0" + abort-controller "^3.0.0" + duplexify "^4.0.0" + google-auth-library "^9.3.0" + node-fetch "^2.6.1" + object-hash "^3.0.0" + proto3-json-serializer "^2.0.2" + protobufjs "^7.3.2" + retry-request "^7.0.0" + uuid "^9.0.1" + google-p12-pem@^3.1.3: version "3.1.4" resolved "https://registry.yarnpkg.com/google-p12-pem/-/google-p12-pem-3.1.4.tgz#123f7b40da204de4ed1fbf2fd5be12c047fc8b3b" @@ -2938,6 +3116,14 @@ gtoken@^5.0.4: google-p12-pem "^3.1.3" jws "^4.0.0" +gtoken@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/gtoken/-/gtoken-7.1.0.tgz#d61b4ebd10132222817f7222b1e6064bd463fc26" + integrity sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw== + dependencies: + gaxios "^6.0.0" + jws "^4.0.0" + har-schema@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" @@ -3040,6 +3226,11 @@ hosted-git-info@^4.0.1, hosted-git-info@^4.0.2: dependencies: lru-cache "^6.0.0" +html-entities@^2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.5.2.tgz#201a3cf95d3a15be7099521620d19dfb4f65359f" + integrity sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA== + http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" @@ -3112,6 +3303,14 @@ https-proxy-agent@^5.0.0: agent-base "6" debug "4" +https-proxy-agent@^7.0.1: + version "7.0.5" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz#9e8b5013873299e11fab6fd548405da2d6c602b2" + integrity sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw== + dependencies: + agent-base "^7.0.2" + debug "4" + humanize-ms@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" @@ -3757,6 +3956,11 @@ mime@1.6.0: resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== +mime@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-3.0.0.tgz#b374550dca3a0c18443b0c950a6a58f1931cf7a7" + integrity sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A== + mimic-response@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" @@ -4017,7 +4221,7 @@ node-addon-api@^2.0.0: resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32" integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA== -node-fetch@^2.6.1, node-fetch@^2.6.12, node-fetch@^2.6.7: +node-fetch@^2.6.1, node-fetch@^2.6.12, node-fetch@^2.6.7, node-fetch@^2.6.9: version "2.7.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== @@ -4375,6 +4579,13 @@ p-cancelable@^3.0.0: resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-3.0.0.tgz#63826694b54d61ca1c20ebcb6d3ecf5e14cd8050" integrity sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw== +p-limit@^3.0.1: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + p-map@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" @@ -4524,6 +4735,13 @@ proto3-json-serializer@^0.1.8: dependencies: protobufjs "^6.11.2" +proto3-json-serializer@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/proto3-json-serializer/-/proto3-json-serializer-2.0.2.tgz#5b705203b4d58f3880596c95fad64902617529dd" + integrity sha512-SAzp/O4Yh02jGdRc+uIrGoe87dkN/XtwxfZ4ZyafJHymd79ozp5VG5nyZ7ygqPM5+cpLDjjGnYFUkngonyDPOQ== + dependencies: + protobufjs "^7.2.5" + protobufjs@6.11.3: version "6.11.3" resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.11.3.tgz#637a527205a35caa4f3e2a9a4a13ddffe0e7af74" @@ -4580,6 +4798,24 @@ protobufjs@^7.2.4: "@types/node" ">=13.7.0" long "^5.0.0" +protobufjs@^7.2.5, protobufjs@^7.3.2: + version "7.3.2" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.3.2.tgz#60f3b7624968868f6f739430cfbc8c9370e26df4" + integrity sha512-RXyHaACeqXeqAKGLDl68rQKbmObRsTIn4TYVUUug1KfS47YWCo5MacGITEryugIgZqORCvJWEk4l449POg5Txg== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/node" ">=13.7.0" + long "^5.0.0" + proxy-addr@~2.0.7: version "2.0.7" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" @@ -4902,6 +5138,20 @@ retry-request@^4.0.0, retry-request@^4.2.2: debug "^4.1.1" extend "^3.0.2" +retry-request@^7.0.0: + version "7.0.2" + resolved "https://registry.yarnpkg.com/retry-request/-/retry-request-7.0.2.tgz#60bf48cfb424ec01b03fca6665dee91d06dd95f3" + integrity sha512-dUOvLMJ0/JJYEn8NrpOaGNE7X3vpI5XlZS/u0ANjqtcZVKnIxP7IgCFwrKTxENw29emmwug53awKtaMm4i9g5w== + dependencies: + "@types/request" "^2.48.8" + extend "^3.0.2" + teeny-request "^9.0.0" + +retry@0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" + integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== + retry@^0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" @@ -5227,6 +5477,11 @@ stream-shift@^1.0.0: resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== +stream-shift@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.3.tgz#85b8fab4d71010fc3ba8772e8046cc49b8a3864b" + integrity sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ== + strict-uri-encode@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" @@ -5310,6 +5565,11 @@ strip-hex-prefix@1.0.0: dependencies: is-hex-prefixed "1.0.0" +strnum@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/strnum/-/strnum-1.0.5.tgz#5c4e829fe15ad4ff0d20c3db5ac97b73c9b072db" + integrity sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA== + stubs@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/stubs/-/stubs-3.0.0.tgz#e8d2ba1fa9c90570303c030b6900f7d5f89abe5b" @@ -5392,6 +5652,17 @@ teeny-request@^7.0.0: stream-events "^1.0.5" uuid "^8.0.0" +teeny-request@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/teeny-request/-/teeny-request-9.0.0.tgz#18140de2eb6595771b1b02203312dfad79a4716d" + integrity sha512-resvxdc6Mgb7YEThw6G6bExlXKkv6+YbuzGg9xuXxSgxJF7Ozs+o8Y9+2R3sArdWdW8nOokoQb1yrpFB0pQK2g== + dependencies: + http-proxy-agent "^5.0.0" + https-proxy-agent "^5.0.0" + node-fetch "^2.6.9" + stream-events "^1.0.5" + uuid "^9.0.0" + text-hex@1.0.x: version "1.0.0" resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5" @@ -5669,6 +5940,11 @@ utils-merge@1.0.1: resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== +uuid@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-10.0.0.tgz#5a95aa454e6e002725c79055fd42aaba30ca6294" + integrity sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ== + uuid@^3.3.2: version "3.4.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" @@ -5679,7 +5955,7 @@ uuid@^8.0.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== -uuid@^9.0.0: +uuid@^9.0.0, uuid@^9.0.1: version "9.0.1" resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== @@ -6179,3 +6455,8 @@ yn@3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==