diff --git a/.gitignore b/.gitignore index 05f8e7f4..1c8c066c 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ cache typechain-types .wrangler .yalc +.vscode diff --git a/arb-verifier/package.json b/arb-verifier/package.json index 1e045a13..393d7d34 100644 --- a/arb-verifier/package.json +++ b/arb-verifier/package.json @@ -26,8 +26,8 @@ "express": "^4.18.2", "ganache": "^7.9.1", "hardhat": "^2.16.0", - "hardhat-deploy": "^0.11.43", - "hardhat-deploy-ethers": "^0.4.1", + "hardhat-deploy": "^0.12.4", + "hardhat-deploy-ethers": "^0.4.2", "hardhat-gas-reporter": "^1.0.8", "solidity-bytes-utils": "^0.8.0", "solidity-coverage": "^0.8.1", diff --git a/bun.lockb b/bun.lockb index d2e2579f..5c4d7419 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/l1-verifier/package.json b/l1-verifier/package.json index fb565e31..1dfe4c36 100644 --- a/l1-verifier/package.json +++ b/l1-verifier/package.json @@ -45,7 +45,7 @@ "typescript": "^5.2.2" }, "dependencies": { - "@ensdomains/evm-verifier": "0.1.0-beta.4", + "@ensdomains/evm-verifier": "workspace:*", "@eth-optimism/contracts": "^0.6.0", "@eth-optimism/contracts-bedrock": "^0.16.2" } diff --git a/op-gateway/op-gateway-lambda/.gitignore b/op-gateway/op-gateway-lambda/.gitignore new file mode 100644 index 00000000..0cb0c32a --- /dev/null +++ b/op-gateway/op-gateway-lambda/.gitignore @@ -0,0 +1,10 @@ +*.js +!jest.config.js +*.d.ts +node_modules + +# CDK asset staging directory +.cdk.staging +cdk.out + +.env \ No newline at end of file diff --git a/op-gateway/op-gateway-lambda/.npmignore b/op-gateway/op-gateway-lambda/.npmignore new file mode 100644 index 00000000..c1d6d45d --- /dev/null +++ b/op-gateway/op-gateway-lambda/.npmignore @@ -0,0 +1,6 @@ +*.ts +!*.d.ts + +# CDK asset staging directory +.cdk.staging +cdk.out diff --git a/op-gateway/op-gateway-lambda/README.md b/op-gateway/op-gateway-lambda/README.md new file mode 100644 index 00000000..a6134223 --- /dev/null +++ b/op-gateway/op-gateway-lambda/README.md @@ -0,0 +1,59 @@ +# Prerequisites + +## Install AWS CLI and CDK + +Refer to https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html for instructions. + +## Configure AWS SSO + +In order to give cdk functions access to your AWS account, configure AWS single sign-on (SSO) to connect to an IAM Identity Centre login. + +See https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sso.html for full details. + +# Deployment + +1. Log into AWS SSO if not already logged in. +``` +aws sso login --profile +``` +The --profile argument can be omitted if the profile is called 'default'. + +2. Set the following environment variables or add to a .env file in this directory. Alternatively these environment variables can be set later in the AWS Lambda function console. + +- L1_PROVIDER_URL +- L2_PROVIDER_URL +- L2_OPTIMISM_PORTAL +- DELAY +- GATEWAY_DOMAIN +- ENDPOINT_URL + +3. Deploy with the following steps +``` +cdk bootstrap +cdk synth +cdk deploy +``` +The lambda url is output towards the end of the last step under 'Outputs' as follows. +``` +Outputs: +OpGatewayLambdaStack.OPGatewayOpGatewayApiEndpoint... = +... +``` +To update an existing lambda function deployment without modifying the url, only the following steps are required. +``` +cdk synth +cdk deploy +``` + +# Removing a deployed lambda function +The lambda function can be taken down with +``` +cdk destroy +``` + +## Other useful commands + +* `npm run build` compile typescript to js +* `npm run watch` watch for changes and compile +* `npm run test` perform the jest unit tests +* `npx cdk diff` compare deployed stack with current state diff --git a/op-gateway/op-gateway-lambda/bin/op-gateway-lambda.ts b/op-gateway/op-gateway-lambda/bin/op-gateway-lambda.ts new file mode 100644 index 00000000..b627aa98 --- /dev/null +++ b/op-gateway/op-gateway-lambda/bin/op-gateway-lambda.ts @@ -0,0 +1,11 @@ +#!/usr/bin/env node +import * as cdk from 'aws-cdk-lib'; +import { OpGatewayLambdaStack } from '../lib/op-gateway-lambda-stack'; + +const app = new cdk.App(); +new OpGatewayLambdaStack(app, 'OpGatewayLambdaStack', { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT, + region: process.env.CDK_DEFAULT_REGION, + }, +}); diff --git a/op-gateway/op-gateway-lambda/bun.lockb b/op-gateway/op-gateway-lambda/bun.lockb new file mode 100755 index 00000000..33050fcc Binary files /dev/null and b/op-gateway/op-gateway-lambda/bun.lockb differ diff --git a/op-gateway/op-gateway-lambda/cdk.json b/op-gateway/op-gateway-lambda/cdk.json new file mode 100644 index 00000000..15ecd0c3 --- /dev/null +++ b/op-gateway/op-gateway-lambda/cdk.json @@ -0,0 +1,80 @@ +{ + "app": "npx ts-node --prefer-ts-exts bin/op-gateway-lambda.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-lambda:recognizeLayerVersion": true, + "@aws-cdk/core:checkSecretUsage": true, + "@aws-cdk/core:target-partitions": [ + "aws", + "aws-cn" + ], + "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, + "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, + "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, + "@aws-cdk/aws-iam:minimizePolicies": true, + "@aws-cdk/core:validateSnapshotRemovalPolicy": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, + "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, + "@aws-cdk/aws-apigateway:disableCloudWatchRole": true, + "@aws-cdk/core:enablePartitionLiterals": true, + "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, + "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true, + "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true, + "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "@aws-cdk/customresources:installLatestAwsSdkDefault": false, + "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true, + "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true, + "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true, + "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true, + "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true, + "@aws-cdk/aws-redshift:columnId": true, + "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true, + "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true, + "@aws-cdk/aws-apigateway:requestValidatorUniqueId": true, + "@aws-cdk/aws-kms:aliasNameRef": true, + "@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true, + "@aws-cdk/core:includePrefixInUniqueNameGeneration": true, + "@aws-cdk/aws-efs:denyAnonymousAccess": true, + "@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true, + "@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true, + "@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true, + "@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true, + "@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true, + "@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true, + "@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": true, + "@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": true, + "@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": true, + "@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2": true, + "@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope": true, + "@aws-cdk/aws-eks:nodegroupNameAttribute": true, + "@aws-cdk/aws-ec2:ebsDefaultGp3Volume": true, + "@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm": true, + "@aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault": false, + "@aws-cdk/aws-s3:keepNotificationInImportedBucket": false, + "@aws-cdk/aws-ecs:reduceEc2FargateCloudWatchPermissions": true, + "@aws-cdk/aws-dynamodb:resourcePolicyPerReplica": true, + "@aws-cdk/aws-ec2:ec2SumTImeoutEnabled": true, + "@aws-cdk/aws-appsync:appSyncGraphQLAPIScopeLambdaPermission": true, + "@aws-cdk/aws-rds:setCorrectValueForDatabaseInstanceReadReplicaInstanceResourceId": true, + "@aws-cdk/core:cfnIncludeRejectComplexResourceUpdateCreatePolicyIntrinsics": true, + "@aws-cdk/aws-lambda-nodejs:sdkV3ExcludeSmithyPackages": true, + "@aws-cdk/aws-stepfunctions-tasks:fixRunEcsTaskPolicy": true + } +} diff --git a/op-gateway/op-gateway-lambda/jest.config.js b/op-gateway/op-gateway-lambda/jest.config.js new file mode 100644 index 00000000..08263b89 --- /dev/null +++ b/op-gateway/op-gateway-lambda/jest.config.js @@ -0,0 +1,8 @@ +module.exports = { + testEnvironment: 'node', + roots: ['/test'], + testMatch: ['**/*.test.ts'], + transform: { + '^.+\\.tsx?$': 'ts-jest' + } +}; diff --git a/op-gateway/op-gateway-lambda/lib/op-gateway-lambda-stack.ts b/op-gateway/op-gateway-lambda/lib/op-gateway-lambda-stack.ts new file mode 100644 index 00000000..8a6def8c --- /dev/null +++ b/op-gateway/op-gateway-lambda/lib/op-gateway-lambda-stack.ts @@ -0,0 +1,10 @@ +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import { OPGateway } from './op-gateway-lambda'; + +export class OpGatewayLambdaStack extends cdk.Stack { + constructor(scope: Construct, id: string, props?: cdk.StackProps) { + super(scope, id, props); + new OPGateway(this, 'OP-Gateway'); + } +} diff --git a/op-gateway/op-gateway-lambda/lib/op-gateway-lambda.function.ts b/op-gateway/op-gateway-lambda/lib/op-gateway-lambda.function.ts new file mode 100644 index 00000000..87db63d5 --- /dev/null +++ b/op-gateway/op-gateway-lambda/lib/op-gateway-lambda.function.ts @@ -0,0 +1,11 @@ +import { Context, APIGatewayProxyResult, APIGatewayEvent } from 'aws-lambda'; +import { gatewayHandler } from '../src/index'; + +export const handler = async ( + event: APIGatewayEvent, + context: Context +): Promise => { + console.log(`Event: ${JSON.stringify(event, null, 2)}`); + console.log(`Context: ${JSON.stringify(context, null, 2)}`); + return gatewayHandler(event, context); +}; diff --git a/op-gateway/op-gateway-lambda/lib/op-gateway-lambda.ts b/op-gateway/op-gateway-lambda/lib/op-gateway-lambda.ts new file mode 100644 index 00000000..5e5c27df --- /dev/null +++ b/op-gateway/op-gateway-lambda/lib/op-gateway-lambda.ts @@ -0,0 +1,27 @@ +import { Construct } from 'constructs'; +import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs'; +import { LambdaRestApi } from 'aws-cdk-lib/aws-apigateway'; +import { Duration } from 'aws-cdk-lib'; +import dotenv from 'dotenv'; + +dotenv.config(); // Load environment variables from .env file + +export class OPGateway extends Construct { + constructor(scope: Construct, id: string) { + super(scope, id); + const opGatewayFunction = new NodejsFunction(this, 'function', { + environment: { + l1_provider_url: process.env.L1_PROVIDER_URL || '', + l2_provider_url: process.env.L2_PROVIDER_URL || '', + l2_optimism_portal: process.env.L2_OPTIMISM_PORTAL || '', + delay: process.env.DELAY || '', + gateway_domain: process.env.GATEWAY_DOMAIN || '', + endpoint_url: process.env.ENDPOINT_URL || '', + }, + timeout: Duration.seconds(15), + }); + new LambdaRestApi(this, 'OpGatewayApi', { + handler: opGatewayFunction, + }); + } +} diff --git a/op-gateway/op-gateway-lambda/package-lock.json b/op-gateway/op-gateway-lambda/package-lock.json new file mode 100644 index 00000000..41aef263 --- /dev/null +++ b/op-gateway/op-gateway-lambda/package-lock.json @@ -0,0 +1,4613 @@ +{ + "name": "op-gateway-lambda", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "op-gateway-lambda", + "version": "0.1.0", + "dependencies": { + "aws-cdk-lib": "2.171.1", + "constructs": "^10.0.0", + "generic-rest-api-router": "^1.2.0" + }, + "bin": { + "op-gateway-lambda": "bin/op-gateway-lambda.js" + }, + "devDependencies": { + "@types/aws-lambda": "^8.10.146", + "@types/debug": "^4.1.12", + "@types/jest": "^29.5.14", + "@types/node": "22.7.9", + "aws-cdk": "2.171.1", + "esbuild": "0.24.0", + "jest": "^29.7.0", + "ts-jest": "^29.2.5", + "ts-node": "^10.9.2", + "typescript": "~5.6.3" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@aws-cdk/asset-awscli-v1": { + "version": "2.2.214", + "resolved": "https://registry.npmjs.org/@aws-cdk/asset-awscli-v1/-/asset-awscli-v1-2.2.214.tgz", + "integrity": "sha512-JeuX1xoYWXEeFD4RyAyvv8OD/NPdbLD6leKKpFLECWqsKY1YrwX0U8lr753CskflwaDGpU42pyyjPdiMZ7NiWA==" + }, + "node_modules/@aws-cdk/asset-kubectl-v20": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@aws-cdk/asset-kubectl-v20/-/asset-kubectl-v20-2.1.3.tgz", + "integrity": "sha512-cDG1w3ieM6eOT9mTefRuTypk95+oyD7P5X/wRltwmYxU7nZc3+076YEVS6vrjDKr3ADYbfn0lDKpfB1FBtO9CQ==" + }, + "node_modules/@aws-cdk/asset-node-proxy-agent-v6": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@aws-cdk/asset-node-proxy-agent-v6/-/asset-node-proxy-agent-v6-2.1.0.tgz", + "integrity": "sha512-7bY3J8GCVxLupn/kNmpPc5VJz8grx+4RKfnnJiO1LG+uxkZfANZG3RMHhE+qQxxwkyQ9/MfPtTpf748UhR425A==" + }, + "node_modules/@aws-cdk/cloud-assembly-schema": { + "version": "38.0.1", + "resolved": "https://registry.npmjs.org/@aws-cdk/cloud-assembly-schema/-/cloud-assembly-schema-38.0.1.tgz", + "integrity": "sha512-KvPe+NMWAulfNVwY7jenFhzhuLhLqJ/OPy5jx7wUstbjnYnjRVLpUHPU3yCjXFE0J8cuJVdx95BJ4rOs66Pi9w==", + "bundleDependencies": [ + "jsonschema", + "semver" + ], + "dependencies": { + "jsonschema": "^1.4.1", + "semver": "^7.6.3" + } + }, + "node_modules/@aws-cdk/cloud-assembly-schema/node_modules/jsonschema": { + "version": "1.4.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/@aws-cdk/cloud-assembly-schema/node_modules/semver": { + "version": "7.6.3", + "inBundle": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.3.tgz", + "integrity": "sha512-nHIxvKPniQXpmQLb0vhY3VaFb3S0YrTAwpOWJZh1wn3oJPjJk9Asva204PsBdmAE8vpzfHudT8DB0scYvy9q0g==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", + "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.26.0", + "@babel/generator": "^7.26.0", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helpers": "^7.26.0", + "@babel/parser": "^7.26.0", + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.26.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.3.tgz", + "integrity": "sha512-6FF/urZvD0sTeO7k6/B15pMLC4CHUv1426lzr3N01aHJTl046uCAh9LXW/fzeXXjPNCJ6iABW5XaWOsIZB93aQ==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.26.3", + "@babel/types": "^7.26.3", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz", + "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", + "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", + "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", + "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", + "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz", + "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.25.9", + "@babel/types": "^7.26.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.3.tgz", + "integrity": "sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.26.3" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", + "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", + "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz", + "integrity": "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", + "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.26.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.4.tgz", + "integrity": "sha512-fH+b7Y4p3yqvApJALCPJcwb0/XaOSgtK4pzV6WVjPR5GLFQBRI7pfoX2V2iM48NXvX07NUxxm1Vw98YjqTcU5w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.3", + "@babel/parser": "^7.26.3", + "@babel/template": "^7.25.9", + "@babel/types": "^7.26.3", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.3.tgz", + "integrity": "sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.0.tgz", + "integrity": "sha512-WtKdFM7ls47zkKHFVzMz8opM7LkcsIp9amDUBIAWirg70RM71WRSjdILPsY5Uv1D42ZpUfaPILDlfactHgsRkw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.0.tgz", + "integrity": "sha512-arAtTPo76fJ/ICkXWetLCc9EwEHKaeya4vMrReVlEIUCAUncH7M4bhMQ+M9Vf+FFOZJdTNMXNBrWwW+OXWpSew==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.0.tgz", + "integrity": "sha512-Vsm497xFM7tTIPYK9bNTYJyF/lsP590Qc1WxJdlB6ljCbdZKU9SY8i7+Iin4kyhV/KV5J2rOKsBQbB77Ab7L/w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.0.tgz", + "integrity": "sha512-t8GrvnFkiIY7pa7mMgJd7p8p8qqYIz1NYiAoKc75Zyv73L3DZW++oYMSHPRarcotTKuSs6m3hTOa5CKHaS02TQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.0.tgz", + "integrity": "sha512-CKyDpRbK1hXwv79soeTJNHb5EiG6ct3efd/FTPdzOWdbZZfGhpbcqIpiD0+vwmpu0wTIL97ZRPZu8vUt46nBSw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.0.tgz", + "integrity": "sha512-rgtz6flkVkh58od4PwTRqxbKH9cOjaXCMZgWD905JOzjFKW+7EiUObfd/Kav+A6Gyud6WZk9w+xu6QLytdi2OA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.0.tgz", + "integrity": "sha512-6Mtdq5nHggwfDNLAHkPlyLBpE5L6hwsuXZX8XNmHno9JuL2+bg2BX5tRkwjyfn6sKbxZTq68suOjgWqCicvPXA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.0.tgz", + "integrity": "sha512-D3H+xh3/zphoX8ck4S2RxKR6gHlHDXXzOf6f/9dbFt/NRBDIE33+cVa49Kil4WUjxMGW0ZIYBYtaGCa2+OsQwQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.0.tgz", + "integrity": "sha512-gJKIi2IjRo5G6Glxb8d3DzYXlxdEj2NlkixPsqePSZMhLudqPhtZ4BUrpIuTjJYXxvF9njql+vRjB2oaC9XpBw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.0.tgz", + "integrity": "sha512-TDijPXTOeE3eaMkRYpcy3LarIg13dS9wWHRdwYRnzlwlA370rNdZqbcp0WTyyV/k2zSxfko52+C7jU5F9Tfj1g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.0.tgz", + "integrity": "sha512-K40ip1LAcA0byL05TbCQ4yJ4swvnbzHscRmUilrmP9Am7//0UjPreh4lpYzvThT2Quw66MhjG//20mrufm40mA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.0.tgz", + "integrity": "sha512-0mswrYP/9ai+CU0BzBfPMZ8RVm3RGAN/lmOMgW4aFUSOQBjA31UP8Mr6DDhWSuMwj7jaWOT0p0WoZ6jeHhrD7g==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.0.tgz", + "integrity": "sha512-hIKvXm0/3w/5+RDtCJeXqMZGkI2s4oMUGj3/jM0QzhgIASWrGO5/RlzAzm5nNh/awHE0A19h/CvHQe6FaBNrRA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.0.tgz", + "integrity": "sha512-HcZh5BNq0aC52UoocJxaKORfFODWXZxtBaaZNuN3PUX3MoDsChsZqopzi5UupRhPHSEHotoiptqikjN/B77mYQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.0.tgz", + "integrity": "sha512-bEh7dMn/h3QxeR2KTy1DUszQjUrIHPZKyO6aN1X4BCnhfYhuQqedHaa5MxSQA/06j3GpiIlFGSsy1c7Gf9padw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.0.tgz", + "integrity": "sha512-ZcQ6+qRkw1UcZGPyrCiHHkmBaj9SiCD8Oqd556HldP+QlpUIe2Wgn3ehQGVoPOvZvtHm8HPx+bH20c9pvbkX3g==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.0.tgz", + "integrity": "sha512-vbutsFqQ+foy3wSSbmjBXXIJ6PL3scghJoM8zCL142cGaZKAdCZHyf+Bpu/MmX9zT9Q0zFBVKb36Ma5Fzfa8xA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.0.tgz", + "integrity": "sha512-hjQ0R/ulkO8fCYFsG0FZoH+pWgTTDreqpqY7UnQntnaKv95uP5iW3+dChxnx7C3trQQU40S+OgWhUVwCjVFLvg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.0.tgz", + "integrity": "sha512-MD9uzzkPQbYehwcN583yx3Tu5M8EIoTD+tUgKF982WYL9Pf5rKy9ltgD0eUgs8pvKnmizxjXZyLt0z6DC3rRXg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.0.tgz", + "integrity": "sha512-4ir0aY1NGUhIC1hdoCzr1+5b43mw99uNwVzhIq1OY3QcEwPDO3B7WNXBzaKY5Nsf1+N11i1eOfFcq+D/gOS15Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.0.tgz", + "integrity": "sha512-jVzdzsbM5xrotH+W5f1s+JtUy1UWgjU0Cf4wMvffTB8m6wP5/kx0KiaLHlbJO+dMgtxKV8RQ/JvtlFcdZ1zCPA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.0.tgz", + "integrity": "sha512-iKc8GAslzRpBytO2/aN3d2yb2z8XTVfNV0PjGlCxKo5SgWmNXx82I/Q3aG1tFfS+A2igVCY97TJ8tnYwpUWLCA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.0.tgz", + "integrity": "sha512-vQW36KZolfIudCcTnaTpmLQ24Ha1RjygBo39/aLkM2kmjkWmZGEJ5Gn9l5/7tzXA42QGIoWbICfg6KLLkIw6yw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.0.tgz", + "integrity": "sha512-7IAFPrjSQIJrGsK6flwg7NFmwBoSTyF3rl7If0hNUFQU4ilTsEPL6GuMuU9BfIWVVGuRnuIidkSMC+c0Otu8IA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "dev": true, + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "dev": true, + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "dev": true, + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, + "node_modules/@types/aws-lambda": { + "version": "8.10.146", + "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.146.tgz", + "integrity": "sha512-3BaDXYTh0e6UCJYL/jwV/3+GRslSc08toAiZSmleYtkAUyV5rtvdPYxrG/88uqvTuT6sb27WE9OS90ZNTIuQ0g==", + "dev": true + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", + "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "dev": true, + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "29.5.14", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.14.tgz", + "integrity": "sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==", + "dev": true, + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "node_modules/@types/ms": { + "version": "0.7.34", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", + "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==", + "dev": true + }, + "node_modules/@types/node": { + "version": "22.7.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.9.tgz", + "integrity": "sha512-jrTfRC7FM6nChvU7X2KqcrgquofrWLFDeYC1hKfwNWomVvrn7JIksqf344WN2X/y8xrgqBd2dJATZV4GbatBfg==", + "dev": true, + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true + }, + "node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true + }, + "node_modules/aws-cdk": { + "version": "2.171.1", + "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.171.1.tgz", + "integrity": "sha512-IWENyT4F5UcLr1szLsbipUdjIHn8FD3d/RvaIvhs2+qCamkfEV5mqv/ChMvRJ8H2jebhIZ2iz74or9O5Ismp+Q==", + "dev": true, + "bin": { + "cdk": "bin/cdk" + }, + "engines": { + "node": ">= 14.15.0" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/aws-cdk-lib": { + "version": "2.171.1", + "resolved": "https://registry.npmjs.org/aws-cdk-lib/-/aws-cdk-lib-2.171.1.tgz", + "integrity": "sha512-BmXodHmeOWu7EZMwXFA+Mp+SnlZgIwhMxfOmqpdGa5dXF4BWOrs0cm4YgrzcJkg0XK713eXPj5IWGj8YeRIU3g==", + "bundleDependencies": [ + "@balena/dockerignore", + "case", + "fs-extra", + "ignore", + "jsonschema", + "minimatch", + "punycode", + "semver", + "table", + "yaml", + "mime-types" + ], + "dependencies": { + "@aws-cdk/asset-awscli-v1": "^2.2.208", + "@aws-cdk/asset-kubectl-v20": "^2.1.3", + "@aws-cdk/asset-node-proxy-agent-v6": "^2.1.0", + "@aws-cdk/cloud-assembly-schema": "^38.0.1", + "@balena/dockerignore": "^1.0.2", + "case": "1.6.3", + "fs-extra": "^11.2.0", + "ignore": "^5.3.2", + "jsonschema": "^1.4.1", + "mime-types": "^2.1.35", + "minimatch": "^3.1.2", + "punycode": "^2.3.1", + "semver": "^7.6.3", + "table": "^6.8.2", + "yaml": "1.10.2" + }, + "engines": { + "node": ">= 14.15.0" + }, + "peerDependencies": { + "constructs": "^10.0.0" + } + }, + "node_modules/aws-cdk-lib/node_modules/@balena/dockerignore": { + "version": "1.0.2", + "inBundle": true, + "license": "Apache-2.0" + }, + "node_modules/aws-cdk-lib/node_modules/ajv": { + "version": "8.17.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/aws-cdk-lib/node_modules/ansi-regex": { + "version": "5.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/aws-cdk-lib/node_modules/ansi-styles": { + "version": "4.3.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/aws-cdk-lib/node_modules/astral-regex": { + "version": "2.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/aws-cdk-lib/node_modules/balanced-match": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/aws-cdk-lib/node_modules/brace-expansion": { + "version": "1.1.11", + "inBundle": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/aws-cdk-lib/node_modules/case": { + "version": "1.6.3", + "inBundle": true, + "license": "(MIT OR GPL-3.0-or-later)", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/aws-cdk-lib/node_modules/color-convert": { + "version": "2.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/aws-cdk-lib/node_modules/color-name": { + "version": "1.1.4", + "inBundle": true, + "license": "MIT" + }, + "node_modules/aws-cdk-lib/node_modules/concat-map": { + "version": "0.0.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/aws-cdk-lib/node_modules/emoji-regex": { + "version": "8.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/aws-cdk-lib/node_modules/fast-deep-equal": { + "version": "3.1.3", + "inBundle": true, + "license": "MIT" + }, + "node_modules/aws-cdk-lib/node_modules/fast-uri": { + "version": "3.0.3", + "inBundle": true, + "license": "BSD-3-Clause" + }, + "node_modules/aws-cdk-lib/node_modules/fs-extra": { + "version": "11.2.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/aws-cdk-lib/node_modules/graceful-fs": { + "version": "4.2.11", + "inBundle": true, + "license": "ISC" + }, + "node_modules/aws-cdk-lib/node_modules/ignore": { + "version": "5.3.2", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/aws-cdk-lib/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/aws-cdk-lib/node_modules/json-schema-traverse": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/aws-cdk-lib/node_modules/jsonfile": { + "version": "6.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/aws-cdk-lib/node_modules/jsonschema": { + "version": "1.4.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/aws-cdk-lib/node_modules/lodash.truncate": { + "version": "4.4.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/aws-cdk-lib/node_modules/mime-db": { + "version": "1.52.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/aws-cdk-lib/node_modules/mime-types": { + "version": "2.1.35", + "inBundle": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/aws-cdk-lib/node_modules/minimatch": { + "version": "3.1.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/aws-cdk-lib/node_modules/punycode": { + "version": "2.3.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/aws-cdk-lib/node_modules/require-from-string": { + "version": "2.0.2", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/aws-cdk-lib/node_modules/semver": { + "version": "7.6.3", + "inBundle": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/aws-cdk-lib/node_modules/slice-ansi": { + "version": "4.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/aws-cdk-lib/node_modules/string-width": { + "version": "4.2.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/aws-cdk-lib/node_modules/strip-ansi": { + "version": "6.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/aws-cdk-lib/node_modules/table": { + "version": "6.8.2", + "inBundle": true, + "license": "BSD-3-Clause", + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/aws-cdk-lib/node_modules/universalify": { + "version": "2.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/aws-cdk-lib/node_modules/yaml": { + "version": "1.10.2", + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "dev": true, + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "dev": true, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz", + "integrity": "sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.24.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", + "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001669", + "electron-to-chromium": "^1.5.41", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.1" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001687", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001687.tgz", + "integrity": "sha512-0S/FDhf4ZiqrTUiQ39dKeUjYRjkv7lOZU1Dgif2rIqrTzX/1wV2hfKu9TOm1IHkdSijfLswxTFzl/cvir+SLSQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.1.tgz", + "integrity": "sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==", + "dev": true + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", + "dev": true + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/constructs": { + "version": "10.4.2", + "resolved": "https://registry.npmjs.org/constructs/-/constructs-10.4.2.tgz", + "integrity": "sha512-wsNxBlAott2qg8Zv87q3eYZYgheb9lchtBfjHzzLHtXbttwSrHPs1NNQbBrmbb1YZvYg2+Vh0Dor76w4mFxJkA==" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dedent": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", + "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", + "dev": true, + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "dev": true, + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.72", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.72.tgz", + "integrity": "sha512-ZpSAUOZ2Izby7qnZluSrAlGgGQzucmFbN0n64dYzocYxnxV5ufurpj3VgEe4cUp7ir9LmeLxNYo8bVnlM8bQHw==", + "dev": true + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/esbuild": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.0.tgz", + "integrity": "sha512-FuLPevChGDshgSicjisSooU0cemp/sGXR841D5LHMB7mTVOmsEHcAxaH3irL53+8YDIeVNQEySh4DaYU/iuPqQ==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.24.0", + "@esbuild/android-arm": "0.24.0", + "@esbuild/android-arm64": "0.24.0", + "@esbuild/android-x64": "0.24.0", + "@esbuild/darwin-arm64": "0.24.0", + "@esbuild/darwin-x64": "0.24.0", + "@esbuild/freebsd-arm64": "0.24.0", + "@esbuild/freebsd-x64": "0.24.0", + "@esbuild/linux-arm": "0.24.0", + "@esbuild/linux-arm64": "0.24.0", + "@esbuild/linux-ia32": "0.24.0", + "@esbuild/linux-loong64": "0.24.0", + "@esbuild/linux-mips64el": "0.24.0", + "@esbuild/linux-ppc64": "0.24.0", + "@esbuild/linux-riscv64": "0.24.0", + "@esbuild/linux-s390x": "0.24.0", + "@esbuild/linux-x64": "0.24.0", + "@esbuild/netbsd-x64": "0.24.0", + "@esbuild/openbsd-arm64": "0.24.0", + "@esbuild/openbsd-x64": "0.24.0", + "@esbuild/sunos-x64": "0.24.0", + "@esbuild/win32-arm64": "0.24.0", + "@esbuild/win32-ia32": "0.24.0", + "@esbuild/win32-x64": "0.24.0" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dev": true, + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/generic-rest-api-router": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/generic-rest-api-router/-/generic-rest-api-router-1.2.0.tgz", + "integrity": "sha512-stc8pgDHTT2wX9qQ/3t1yYfIFantXqNomil3GRPZgAF2U2oGMJ8+3ufanGzdxTUYr20L3fJZrFPF9/pO5LS7QA==", + "dependencies": { + "http-status-codes": "^2.2.0", + "jwt-decode": "^3.1.2", + "node-match-path": "^0.6.3", + "uuid": "3.4.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/http-status-codes": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/http-status-codes/-/http-status-codes-2.3.0.tgz", + "integrity": "sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA==" + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-core-module": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", + "dev": true, + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jake": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", + "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", + "dev": true, + "dependencies": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.4", + "minimatch": "^3.1.2" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "dev": true, + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "dev": true, + "dependencies": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dev": true, + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "dev": true, + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "dev": true, + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "dev": true, + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jwt-decode": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", + "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true + }, + "node_modules/node-match-path": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/node-match-path/-/node-match-path-0.6.3.tgz", + "integrity": "sha512-fB1reOHKLRZCJMAka28hIxCwQLxGmd7WewOCBDYKpyA1KXi68A7vaGgdZAPhY2E6SXoYt3KqYCCvXLJ+O0Fu/Q==" + }, + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ] + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", + "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-jest": { + "version": "29.2.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.2.5.tgz", + "integrity": "sha512-KD8zB2aAZrcKIdGk4OwpJggeLcH1FgrICqDSROWqlnJXGCXK4Mn6FcdK2B6670Xr73lHMG1kHw8R87A0ecZ+vA==", + "dev": true, + "dependencies": { + "bs-logger": "^0.2.6", + "ejs": "^3.1.10", + "fast-json-stable-stringify": "^2.1.0", + "jest-util": "^29.0.0", + "json5": "^2.2.3", + "lodash.memoize": "^4.1.2", + "make-error": "^1.3.6", + "semver": "^7.6.3", + "yargs-parser": "^21.1.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/transform": "^29.0.0", + "@jest/types": "^29.0.0", + "babel-jest": "^29.0.0", + "jest": "^29.0.0", + "typescript": ">=4.3 <6" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/transform": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, + "node_modules/ts-jest/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true + }, + "node_modules/update-browserslist-db": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/op-gateway/op-gateway-lambda/package.json b/op-gateway/op-gateway-lambda/package.json new file mode 100644 index 00000000..515347ae --- /dev/null +++ b/op-gateway/op-gateway-lambda/package.json @@ -0,0 +1,37 @@ +{ + "name": "op-gateway-lambda", + "version": "0.1.0", + "bin": { + "op-gateway-lambda": "bin/op-gateway-lambda.js" + }, + "scripts": { + "build:cjs": "tsc --module commonjs --outDir ./_cjs --removeComments --verbatimModuleSyntax false && echo > ./_cjs/package.json '{\"type\":\"commonjs\"}'", + "build:esm": "tsc --module es2022 --outDir ./_esm && echo > ./_esm/package.json '{\"type\":\"module\",\"sideEffects\":false}'", + "build:types": "tsc --module esnext --declarationDir ./_types --emitDeclarationOnly --declaration --declarationMap", + "build": "echo 'building op-gateway-lambda...' && bun run clean && bun run build:cjs && bun run build:esm && bun run build:types", + "prepublishOnly": "bun run build", + "lint": "eslint . --ext .ts", + "prepare": "bun run build", + "clean": "rm -fr _cjs _esm _types", + "watch": "tsc -w", + "test": "jest", + "cdk": "cdk" + }, + "devDependencies": { + "@types/aws-lambda": "^8.10.146", + "@types/debug": "^4.1.12", + "@types/jest": "^29.5.14", + "@types/node": "22.7.9", + "aws-cdk": "2.171.1", + "esbuild": "0.24.0", + "jest": "^29.7.0", + "ts-jest": "^29.2.5", + "ts-node": "^10.9.2", + "typescript": "~5.6.3" + }, + "dependencies": { + "aws-cdk-lib": "2.171.1", + "constructs": "^10.0.0", + "generic-rest-api-router": "^1.2.0" + } +} diff --git a/op-gateway/op-gateway-lambda/src/AWSFunctionRouter.ts b/op-gateway/op-gateway-lambda/src/AWSFunctionRouter.ts new file mode 100644 index 00000000..37ac6fa5 --- /dev/null +++ b/op-gateway/op-gateway-lambda/src/AWSFunctionRouter.ts @@ -0,0 +1,30 @@ +import { APIGatewayProxyResult } from 'aws-lambda'; +import { FunctionRouter } from 'generic-rest-api-router'; +import { AwsRequestContext } from './AWSRequestContext'; + +/** + * Defines an AWS Lambda REST API and the functions that will be invoked for all matching + * HTTP methods and paths. The template variable T refers to the resource being handled + * by this REST API. + */ +export class AwsFunctionRouter extends FunctionRouter { + /** + * Calls the appropriate Handler based on the HTTP method and path found in the + * requestContext. Returns the result of the handler execution as an + * APIGatewayProxyResult. + * + * @param requestContext + * @returns handler result + */ + async handle( + requestContext: AwsRequestContext + ): Promise { + const response = await super.handleRequest(requestContext); + + return { + headers: response.headers, + statusCode: response.statusCode, + body: response.body || '', + }; + } +} diff --git a/op-gateway/op-gateway-lambda/src/AWSRequestContext.ts b/op-gateway/op-gateway-lambda/src/AWSRequestContext.ts new file mode 100644 index 00000000..6aa2fbe2 --- /dev/null +++ b/op-gateway/op-gateway-lambda/src/AWSRequestContext.ts @@ -0,0 +1,25 @@ +import { APIGatewayProxyEvent, Context } from 'aws-lambda'; +import { RequestContext } from 'generic-rest-api-router'; + +/** + * Implementation of the RequestContext interface that makes the AWS Lambda + * APIGatewayProxyEvent and Context available to a handler. + */ +export class AwsRequestContext implements RequestContext { + constructor( + public event: APIGatewayProxyEvent, + public context: Context + ) {} + + getHttpMethod(): string { + return this.event.requestContext.httpMethod; + } + + getPath(): string { + return this.event.path; + } + + getBody(): string { + return this.event.body || ''; + } +} diff --git a/op-gateway/op-gateway-lambda/src/aws-lambda-ccip-router.ts b/op-gateway/op-gateway-lambda/src/aws-lambda-ccip-router.ts new file mode 100644 index 00000000..b0020dd8 --- /dev/null +++ b/op-gateway/op-gateway-lambda/src/aws-lambda-ccip-router.ts @@ -0,0 +1,194 @@ +//import { ethers, BytesLike, AbiCoder, hexlify, Fragment, FunctionFragment, Interface, JsonFragment } from 'ethers'; +import { + Fragment, + FunctionFragment, + Interface, + JsonFragment, + Result, + defaultAbiCoder, +} from '@ethersproject/abi'; +import { hexlify, BytesLike, isBytesLike } from '@ethersproject/bytes'; +import { isAddress } from '@ethersproject/address'; +//import { isAddress, isBytesLike } from 'ethers'; + +import { AwsFunctionRouter } from './AWSFunctionRouter'; +import { FunctionResponse } from 'generic-rest-api-router'; + +export interface RPCCall { + to: BytesLike; + data: BytesLike; +} + +export interface RPCResponse { + status: number; + body: RPCResponseBody; +} + +type RPCResponseBody = { + data?: string; + message?: string; +}; + +export type HandlerFunc = ( + args: Result, + req: RPCCall +) => Promise> | Array; + +export interface HandlerDescription { + type: string; + func: HandlerFunc; +} +interface Handler { + type: FunctionFragment; + func: HandlerFunc; +} + +function toInterface( + abi: string | readonly (string | Fragment | JsonFragment)[] | Interface +) { + if (Interface.isInterface(abi)) { + return abi; + } + return new Interface(abi); +} + +function getFunctionSelector(calldata: string): string { + return calldata.slice(0, 10).toLowerCase(); +} + +export class ServerLambda { + /** @ignore */ + readonly handlers: { [selector: string]: Handler }; + + /** + * Constructs a new CCIP-Read gateway server instance. + */ + constructor() { + this.handlers = {}; + } + + /** + * Adds an interface to the gateway server, with handlers to handle some or all of its functions. + * @param abi The contract ABI to use. This can be in any format that ethers.js recognises, including + * a 'Human Readable ABI', a JSON-format ABI, or an Ethers `Interface` object. + * @param handlers An array of handlers to register against this interface. + */ + add( + abi: string | readonly (string | Fragment | JsonFragment)[] | Interface, + handlers: Array + ) { + const abiInterface = toInterface(abi); + + for (const handler of handlers) { + const fn = abiInterface.getFunction(handler.type); + + this.handlers[Interface.getSighash(fn)] = { + type: fn, + func: handler.func, + }; + } + } + + /** + * // set up server object here + * const app = server.makeApp(''); + * module.exports = { + * fetch: function (request, _env, _context) { + * return app.handle(request) + * } + * }; + * ``` + * The path prefix to `makeApp` will have sender and callData arguments appended. + * If your server is on example.com and configured as above, the URL template to use + * in a smart contract would be "https://example.com/{sender}/{callData}.json". + * @returns An `itty-router.Router` object configured to serve as a CCIP read gateway. + */ + makeApp(prefix: string) { + const app = new AwsFunctionRouter({ + resourcePath: prefix, + includeCORS: true, + }) + .get('', async (route) => { + return route.okResponse('hey ho!'); + }) + .get('/:sender/:callData.json', async (route, requestContext) => { + const sender = route.getPathParams(requestContext).sender; + const callData = route.getPathParams(requestContext).callData; + if (!isAddress(sender) || !isBytesLike(callData)) { + return route.errorResponse(400); + } + + try { + const response = await this.call({ to: sender, data: callData }); + const ret: FunctionResponse = { + statusCode: response.status, + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(response.body), + }; + return ret; + } catch (e) { + return route.errorResponse(500); + } + }) + .post('', async (route, requestContext) => { + const requestBody = JSON.parse(requestContext.getBody()); + const sender = requestBody.sender; + const callData = requestBody.data; + + if (!isAddress(sender) || !isBytesLike(callData)) { + return route.errorResponse(400); + } + + try { + const response = await this.call({ to: sender, data: callData }); + const ret: FunctionResponse = { + statusCode: response.status, + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(response.body), + }; + return ret; + } catch (e) { + return route.errorResponse(500); + } + }); + return app; + } + + async call(call: RPCCall): Promise { + const calldata = hexlify(call.data); + const selector = getFunctionSelector(calldata); + + // Find a function handler for this selector + const handler = this.handlers[selector]; + if (!handler) { + return { + status: 404, + body: { + message: `No implementation for function with selector ${selector}`, + }, + }; + } + + const args = defaultAbiCoder.decode( + handler.type.inputs, + '0x' + calldata.slice(10) + ); + + // Call the handler + const result = await handler.func(args, call); + + // Encode return data + return { + status: 200, + body: { + data: handler.type.outputs + ? hexlify(defaultAbiCoder.encode(handler.type.outputs, result)) + : '0x', + }, + }; + } +} diff --git a/op-gateway/op-gateway-lambda/src/aws-lambda-tracker.ts b/op-gateway/op-gateway-lambda/src/aws-lambda-tracker.ts new file mode 100644 index 00000000..cd6188dd --- /dev/null +++ b/op-gateway/op-gateway-lambda/src/aws-lambda-tracker.ts @@ -0,0 +1,156 @@ +import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda'; + +interface TrackerOptions { + apiEndpoint?: string; + enableLogging?: boolean; +} + +interface TrackingOptions { + props?: { [key: string]: number | string } | string | number; + data?: { [key: string]: number | string } | string | number; +} + +interface RequestBody { + domain: string; + name: string; + url: string; + referrer?: string; + props?: { [key: string]: number | string } | string | number; + data?: { [key: string]: number | string } | string | number; +} + +interface LogResponse { + data: string; +} + +export type PropsDecoderLambda = ( + request?: T, + response?: string +) => { + [key: string]: any; +}; + +export class TrackerLambda< + T extends APIGatewayProxyEvent = APIGatewayProxyEvent, +> { + domain = ''; + enableLogging = false; + apiEndpoint = 'https://plausible.io/api/event'; + + constructor(domain: string, options: TrackerOptions = {}) { + this.domain = domain; + this.apiEndpoint = options.apiEndpoint || this.apiEndpoint; + this.enableLogging = options.enableLogging || this.enableLogging; + } + + private log(message: string) { + if (this.enableLogging) { + console.log(message); + } + } + + private getUrl(req: T): string { + return `http://${req.requestContext.domainName}${req.path}`; + } + + async trackPageview( + req: T, + options?: TrackingOptions, + includeUserDetails?: boolean + ) { + await this.trackEvent(req, 'pageview', options, includeUserDetails); + } + + async trackEvent( + req: T, + name: string, + { props, data }: TrackingOptions = {}, + includeUserDetails = false + ): Promise { + try { + if (!name || typeof name !== 'string') { + throw new Error('Invalid event name'); + } + + const body: RequestBody = { + domain: this.domain, + name: name, + url: this.getUrl(req), + }; + + if (req.headers['Referrer']) { + body.referrer = req.headers['Referrer'] || ''; + } + + if (props) { + body.props = props; + } + + if (data) { + body.data = data; + } + + const headers: HeadersInit = { + 'Content-Type': 'application/json', + }; + + const userAgent = req.headers['User-Agent']; + if (userAgent) { + headers['User-Agent'] = userAgent; + headers['X-Forwarded-For'] = '127.0.0.1'; + } + + if (includeUserDetails) { + headers['X-Forwarded-For'] = req.requestContext.identity.sourceIp; + } + + this.log(JSON.stringify(headers)); + this.log(JSON.stringify(body)); + + const response = await fetch(this.apiEndpoint, { + method: 'POST', + headers: headers, + body: JSON.stringify(body), + }); + + if (!response.ok) { + throw new Error(`Plausible API responded with ${response.status}`); + } else { + this.log(`Event tracked: ${name}`); + } + } catch (err) { + console.error(`Plausible error: ${err}`); + } + } + + private getStructuredResult(result: APIGatewayProxyResult) { + if (typeof result === 'string') { + return JSON.parse(result); + } else return result; + } + + async logResult( + decoder: PropsDecoderLambda = () => ({}), + req: T, + resp: APIGatewayProxyResult + ): Promise { + const res = this.getStructuredResult(resp); + if (!res.body) { + return resp; + } + try { + const response: LogResponse = { + data: resp.body, + }; + + const props = { + result: response.data.substring(0, 200), + ...(!!decoder && decoder(req, response.data)), + }; + await this.trackEvent(req, 'result', { props }, true); + } catch (error) { + this.log(`logResult error: ${error}`); + } + return resp; + } +} diff --git a/op-gateway/op-gateway-lambda/src/index.ts b/op-gateway/op-gateway-lambda/src/index.ts new file mode 100644 index 00000000..983a410c --- /dev/null +++ b/op-gateway/op-gateway-lambda/src/index.ts @@ -0,0 +1,80 @@ +import { ServerLambda } from './aws-lambda-ccip-router'; +import { TrackerLambda, PropsDecoderLambda } from './aws-lambda-tracker'; +import { EVMGateway } from '@ensdomains/evm-gateway'; +import { OPProofService } from '../../src/OPProofService'; +import { JsonRpcProvider } from 'ethers'; +import { + APIGatewayProxyEvent, + APIGatewayProxyResult, + Context, +} from 'aws-lambda'; +import { AwsRequestContext } from './AWSRequestContext'; + +interface RouterLambda { + handle: (request: AwsRequestContext) => Promise; +} + +let app: RouterLambda; + +export const gatewayHandler = async ( + event: APIGatewayProxyEvent, + context: Context +): Promise => { + const L1_PROVIDER_URL: string = process.env.l1_provider_url || ''; + const L2_PROVIDER_URL: string = process.env.l2_provider_url || ''; + const L2_OPTIMISM_PORTAL: string = process.env.l2_optimism_portal || ''; + const DELAY: string = process.env.delay || ''; + const GATEWAY_DOMAIN: string = process.env.gateway_domain || ''; + const ENDPOINT_URL: string = process.env.endpoint_url || ''; + + const tracker = new TrackerLambda(GATEWAY_DOMAIN, { + apiEndpoint: ENDPOINT_URL, + enableLogging: true, + }); + + if (!app) { + const l1Provider = new JsonRpcProvider(L1_PROVIDER_URL); + const l2Provider = new JsonRpcProvider(L2_PROVIDER_URL); + + console.log({ L1_PROVIDER_URL, L2_PROVIDER_URL, DELAY }); + const gateway = new EVMGateway( + new OPProofService( + l1Provider, + l2Provider, + L2_OPTIMISM_PORTAL, + Number(DELAY) + ) + ); + + const server = new ServerLambda(); + gateway.add(server); + app = server.makeApp(''); + } + + const props = propsDecoderAWS(event); + await tracker.trackEvent(event, 'request', { props }, true); + + const requestContext = new AwsRequestContext(event, context); + return app + .handle(requestContext) + .then(tracker.logResult.bind(tracker, propsDecoderAWS, event)); +}; + +const propsDecoderAWS: PropsDecoderLambda = ( + request?: APIGatewayProxyEvent +) => { + if (!request || !request.path) { + return {}; + } + const trackingData = request.path.match( + /\/0x[a-fA-F0-9]{40}\/0x[a-fA-F0-9]{1,}\.json/ + ); + if (trackingData) { + return { + sender: trackingData[0].slice(1, 42), + calldata: trackingData[0].slice(44).replace('.json', ''), + }; + } else { + return {}; + } +}; diff --git a/op-gateway/op-gateway-lambda/test/op-gateway-lambda.test.ts b/op-gateway/op-gateway-lambda/test/op-gateway-lambda.test.ts new file mode 100644 index 00000000..cbc36b81 --- /dev/null +++ b/op-gateway/op-gateway-lambda/test/op-gateway-lambda.test.ts @@ -0,0 +1,17 @@ +// import * as cdk from 'aws-cdk-lib'; +// import { Template } from 'aws-cdk-lib/assertions'; +// import * as OpGatewayLambda from '../lib/op-gateway-lambda-stack'; + +// example test. To run these tests, uncomment this file along with the +// example resource in lib/op-gateway-lambda-stack.ts +test('SQS Queue Created', () => { + // const app = new cdk.App(); + // // WHEN + // const stack = new OpGatewayLambda.OpGatewayLambdaStack(app, 'MyTestStack'); + // // THEN + // const template = Template.fromStack(stack); + // + // template.hasResourceProperties('AWS::SQS::Queue', { + // VisibilityTimeout: 300 + // }); +}); diff --git a/op-gateway/op-gateway-lambda/tsconfig.json b/op-gateway/op-gateway-lambda/tsconfig.json new file mode 100644 index 00000000..edc31c15 --- /dev/null +++ b/op-gateway/op-gateway-lambda/tsconfig.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "moduleResolution": "Node", + "lib": [ + "es2020", + "dom" + ], + "esModuleInterop": true, + "declaration": true, + "strict": true, + "noImplicitAny": true, + "strictNullChecks": true, + "noImplicitThis": true, + "alwaysStrict": true, + "noUnusedLocals": false, + "noUnusedParameters": false, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": false, + "inlineSourceMap": true, + "inlineSources": true, + "experimentalDecorators": true, + "strictPropertyInitialization": false, + "typeRoots": [ + "./node_modules/@types" + ] + }, + "exclude": [ + "node_modules", + "cdk.out" + ] +} diff --git a/op-gateway/package.json b/op-gateway/package.json index 55aee90d..276b0be2 100644 --- a/op-gateway/package.json +++ b/op-gateway/package.json @@ -59,7 +59,7 @@ "@chainlink/ccip-read-server": "^0.2.1", "@cloudflare/workers-types": "^4.20240423.0", "@commander-js/extra-typings": "^11.0.0", - "@ensdomains/evm-gateway": "0.1.0-beta.4", + "@ensdomains/evm-gateway": "workspace:*", "@ensdomains/server-analytics": "0.0.1-alpha.5", "@ethereumjs/block": "^5.0.0", "@nomicfoundation/ethereumjs-block": "^5.0.2", diff --git a/op-gateway/src/OPOutputLookup.ts b/op-gateway/src/OPOutputLookup.ts new file mode 100644 index 00000000..8d13ff8c --- /dev/null +++ b/op-gateway/src/OPOutputLookup.ts @@ -0,0 +1,249 @@ +export default [ + { + "type": "function", + "name": "getDisputeGame", + "inputs": [ + { + "name": "optimismPortal", + "type": "address", + "internalType": "contract IOptimismPortalOutputRoot" + }, + { "name": "index", "type": "uint256", "internalType": "uint256" }, + { "name": "minAge", "type": "uint256", "internalType": "uint256" }, + { "name": "maxAge", "type": "uint256", "internalType": "uint256" } + ], + "outputs": [ + { "name": "outputRoot", "type": "bytes32", "internalType": "bytes32" }, + { "name": "gameType", "type": "uint32", "internalType": "GameType" }, + { + "name": "gameCreationTime", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "proxy", + "type": "address", + "internalType": "contract IDisputeGame" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getL2Output", + "inputs": [ + { + "name": "optimismPortal", + "type": "address", + "internalType": "contract IOptimismPortalOutputRoot" + }, + { "name": "index", "type": "uint256", "internalType": "uint256" }, + { "name": "minAge", "type": "uint256", "internalType": "uint256" }, + { "name": "maxAge", "type": "uint256", "internalType": "uint256" } + ], + "outputs": [ + { + "name": "", + "type": "tuple", + "internalType": "struct Types.OutputProposal", + "components": [ + { + "name": "outputRoot", + "type": "bytes32", + "internalType": "bytes32" + }, + { "name": "timestamp", "type": "uint128", "internalType": "uint128" }, + { + "name": "l2BlockNumber", + "type": "uint128", + "internalType": "uint128" + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getLatestDisputeGame", + "inputs": [ + { + "name": "optimismPortal", + "type": "address", + "internalType": "contract IOptimismPortalOutputRoot" + }, + { "name": "gameType", "type": "uint32", "internalType": "GameType" }, + { "name": "minAge", "type": "uint256", "internalType": "uint256" }, + { "name": "maxAge", "type": "uint256", "internalType": "uint256" } + ], + "outputs": [ + { + "name": "disputeGameIndex", + "type": "uint256", + "internalType": "uint256" + }, + { "name": "outputRoot", "type": "bytes32", "internalType": "bytes32" }, + { + "name": "gameCreationTime", + "type": "uint64", + "internalType": "uint64" + }, + { "name": "blockNumber", "type": "uint256", "internalType": "uint256" }, + { + "name": "proxy", + "type": "address", + "internalType": "contract IDisputeGame" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getLatestL2Output", + "inputs": [ + { + "name": "optimismPortal", + "type": "address", + "internalType": "contract IOptimismPortalOutputRoot" + }, + { "name": "minAge", "type": "uint256", "internalType": "uint256" }, + { "name": "maxAge", "type": "uint256", "internalType": "uint256" } + ], + "outputs": [ + { "name": "index", "type": "uint256", "internalType": "uint256" }, + { + "name": "", + "type": "tuple", + "internalType": "struct Types.OutputProposal", + "components": [ + { + "name": "outputRoot", + "type": "bytes32", + "internalType": "bytes32" + }, + { "name": "timestamp", "type": "uint128", "internalType": "uint128" }, + { + "name": "l2BlockNumber", + "type": "uint128", + "internalType": "uint128" + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getLatestRespectedDisputeGame", + "inputs": [ + { + "name": "optimismPortal", + "type": "address", + "internalType": "contract IOptimismPortalOutputRoot" + }, + { "name": "minAge", "type": "uint256", "internalType": "uint256" }, + { "name": "maxAge", "type": "uint256", "internalType": "uint256" } + ], + "outputs": [ + { + "name": "disputeGameIndex", + "type": "uint256", + "internalType": "uint256" + }, + { "name": "outputRoot", "type": "bytes32", "internalType": "bytes32" }, + { + "name": "gameCreationTime", + "type": "uint64", + "internalType": "uint64" + }, + { "name": "blockNumber", "type": "uint256", "internalType": "uint256" }, + { + "name": "proxy", + "type": "address", + "internalType": "contract IDisputeGame" + }, + { "name": "gameType", "type": "uint32", "internalType": "GameType" } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getOPProvableBlock", + "inputs": [ + { + "name": "optimismPortal", + "type": "address", + "internalType": "contract IOptimismPortalOutputRoot" + }, + { "name": "minAge", "type": "uint256", "internalType": "uint256" }, + { "name": "maxAge", "type": "uint256", "internalType": "uint256" } + ], + "outputs": [ + { + "name": "result", + "type": "tuple", + "internalType": "struct OPProvableBlock", + "components": [ + { + "name": "proofType", + "type": "uint8", + "internalType": "enum OPWitnessProofType" + }, + { "name": "index", "type": "uint256", "internalType": "uint256" }, + { + "name": "blockNumber", + "type": "uint256", + "internalType": "uint256" + }, + { "name": "outputRoot", "type": "bytes32", "internalType": "bytes32" } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getProofType", + "inputs": [ + { + "name": "optimismPortal", + "type": "address", + "internalType": "contract IOptimismPortalOutputRoot" + } + ], + "outputs": [ + { "name": "", "type": "uint8", "internalType": "enum OPWitnessProofType" } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getRespectedDisputeGame", + "inputs": [ + { + "name": "optimismPortal", + "type": "address", + "internalType": "contract IOptimismPortalOutputRoot" + }, + { "name": "index", "type": "uint256", "internalType": "uint256" }, + { "name": "minAge", "type": "uint256", "internalType": "uint256" }, + { "name": "maxAge", "type": "uint256", "internalType": "uint256" } + ], + "outputs": [ + { "name": "outputRoot", "type": "bytes32", "internalType": "bytes32" }, + { "name": "gameType", "type": "uint32", "internalType": "GameType" }, + { + "name": "gameCreationTime", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "proxy", + "type": "address", + "internalType": "contract IDisputeGame" + } + ], + "stateMutability": "view" + }, + { "type": "error", "name": "UnknownProofType", "inputs": [] } +] as const diff --git a/op-gateway/src/OPProofService.ts b/op-gateway/src/OPProofService.ts index f3009042..5f52d88a 100644 --- a/op-gateway/src/OPProofService.ts +++ b/op-gateway/src/OPProofService.ts @@ -5,72 +5,100 @@ import { } from '@ensdomains/evm-gateway'; import { type JsonRpcBlock } from '@ethereumjs/block'; import { AbiCoder, Contract, JsonRpcProvider, type AddressLike } from 'ethers'; +import OPOutputLookupABI from './OPOutputLookup.js' + +export class InvalidOptimismPortalError extends Error { + constructor() { + super('OptimismPortal is invalid'); + } +} + +export class DisputeGameChallengedError extends Error { + constructor() { + super('Dispute game is challenged'); + } +} + +export enum OPWitnessProofType { + L2OutputOracle = 0, + DisputeGame = 1, +} export interface OPProvableBlock { number: number; - l2OutputIndex: number; + proofType: OPWitnessProofType; + index: number; } -const L2_OUTPUT_ORACLE_ABI = [ - 'function latestOutputIndex() external view returns (uint256)', - 'function getL2Output(uint256 _l2OutputIndex) external view returns (tuple(bytes32 outputRoot, uint128 timestamp, uint128 l2BlockNumber))', -]; +// OPOutputLookup contract is deployed with deterministic deployment +// As a result, OPOutputLookup is always deployed to the same address +// See OPOutputLookup.sol on op-verifier/contracts/OPOutputLookup.sol +const OP_OUTPUT_LOOKUP = "0x475dc200b71dbd9776518C299e281766FaDf4A30" const L2_TO_L1_MESSAGE_PASSER_ADDRESS = '0x4200000000000000000000000000000000000016'; +const OPTIMISM_PORTAL_ABI = [ + 'function l2Oracle() external view returns (address)', + 'function disputeGameFactory() external view returns (address)', + 'function respectedGameType() external view returns (uint32)', +]; + /** * The proofService class can be used to calculate proofs for a given target and slot on the Optimism Bedrock network. * It's also capable of proofing long types such as mappings or string by using all included slots in the proof. * */ export class OPProofService implements IProofService { - private readonly l2OutputOracle: Contract; + private readonly l1Provider: JsonRpcProvider; private readonly l2Provider: JsonRpcProvider; private readonly helper: EVMProofHelper; - private readonly delay: number; + private readonly minAge: number; + + private readonly optimismPortal: Contract; + private opOutputLookup: Contract; constructor( l1Provider: JsonRpcProvider, l2Provider: JsonRpcProvider, - l2OutputOracleAddress: string, - delay: number + optimismPortalAddress: string, + minAge: number ) { + this.l1Provider = l1Provider; this.l2Provider = l2Provider; this.helper = new EVMProofHelper(l2Provider); - this.delay = delay; - this.l2OutputOracle = new Contract( - l2OutputOracleAddress, - L2_OUTPUT_ORACLE_ABI, - l1Provider + this.minAge = minAge; + + this.optimismPortal = new Contract( + optimismPortalAddress, + OPTIMISM_PORTAL_ABI, + this.l1Provider ); + + this.opOutputLookup = new Contract( + OP_OUTPUT_LOOKUP, + OPOutputLookupABI, + this.l1Provider, + ) } /** * @dev Returns an object representing a block whose state can be proven on L1. */ async getProvableBlock(): Promise { - /** - * Get the latest output from the L2Oracle. We're building the proof with this batch - * We go a few batches backwards to avoid errors like delays between nodes - * - */ - const l2OutputIndex = - Number(await this.l2OutputOracle.latestOutputIndex()) - this.delay; - - /** - * struct OutputProposal { - * bytes32 outputRoot; - * uint128 timestamp; - * uint128 l2BlockNumber; - * } - */ - const outputProposal = await this.l2OutputOracle.getL2Output(l2OutputIndex); + const block = await this.opOutputLookup.getOPProvableBlock( + await this.optimismPortal.getAddress(), + this.minAge, + 1000000000 // Unlimited maximum age + ) + + console.log(block) return { - number: outputProposal.l2BlockNumber, - l2OutputIndex: l2OutputIndex, - }; + number: block.blockNumber, + proofType: block.proofType, + index: block.index, + } } /** @@ -112,13 +140,14 @@ export class OPProofService implements IProofService { return AbiCoder.defaultAbiCoder().encode( [ - 'tuple(uint256 l2OutputIndex, tuple(bytes32 version, bytes32 stateRoot, bytes32 messagePasserStorageRoot, bytes32 latestBlockhash) outputRootProof)', + 'tuple(uint8 proofType, uint256 index, tuple(bytes32 version, bytes32 stateRoot, bytes32 messagePasserStorageRoot, bytes32 latestBlockhash) outputRootProof)', 'tuple(bytes stateTrieWitness, bytes[] storageProofs)', ], [ { blockNo: block.number, - l2OutputIndex: block.l2OutputIndex, + proofType: block.proofType, + index: block.index, outputRootProof: { version: '0x0000000000000000000000000000000000000000000000000000000000000000', diff --git a/op-gateway/src/server.ts b/op-gateway/src/server.ts index 7c163127..b22ad9c4 100644 --- a/op-gateway/src/server.ts +++ b/op-gateway/src/server.ts @@ -17,8 +17,8 @@ const program = new Command() 'http://localhost:9545/' ) .option( - '-o --l2-output-oracle
', - 'address for L2 output oracle on the L1', + '-o --l2-optimism-portal
', + 'address for OptimismPortalProxy on the L1', '' ) .option('-d, --delay ', 'number of blocks delay to use', '5'); @@ -35,7 +35,7 @@ program.parse(); new OPProofService( l1Provider, l2Provider, - options.l2OutputOracle, + options.l2OptimismPortal, Number(options.delay) ) ); diff --git a/op-gateway/src/worker.ts b/op-gateway/src/worker.ts index 12719b88..2368d6da 100644 --- a/op-gateway/src/worker.ts +++ b/op-gateway/src/worker.ts @@ -6,7 +6,7 @@ import { Tracker } from '@ensdomains/server-analytics'; interface Env { L1_PROVIDER_URL: string; L2_PROVIDER_URL: string; - L2_OUTPUT_ORACLE: string; + L2_OPTIMISM_PORTAL: string; DELAY: number; GATEWAY_DOMAIN: string; ENDPOINT_URL: string; @@ -19,7 +19,7 @@ async function fetch(request: CFWRequest, env: Env) { const { L1_PROVIDER_URL, L2_PROVIDER_URL, - L2_OUTPUT_ORACLE, + L2_OPTIMISM_PORTAL, DELAY, GATEWAY_DOMAIN, ENDPOINT_URL, @@ -44,7 +44,7 @@ async function fetch(request: CFWRequest, env: Env) { new OPProofService( l1Provider, l2Provider, - L2_OUTPUT_ORACLE, + L2_OPTIMISM_PORTAL, Number(DELAY) ) ); diff --git a/op-verifier/.gitignore b/op-verifier/.gitignore index 3360da73..0151edc6 100644 --- a/op-verifier/.gitignore +++ b/op-verifier/.gitignore @@ -10,3 +10,4 @@ cache artifacts deployments +test/testOPGateway.ts \ No newline at end of file diff --git a/op-verifier/README.md b/op-verifier/README.md index bb4249a4..de2a67e4 100644 --- a/op-verifier/README.md +++ b/op-verifier/README.md @@ -63,6 +63,21 @@ The tests will require small modifications to work on public testnets; specifica - https://base-sepolia-gateway-worker.ens-cf.workers.dev/{sender}/{data}.json +## OPOutputLookup + +* Address: 0x475dc200b71dbd9776518C299e281766FaDf4A30 +* Deterministic Deployment Proxy: 0x4e59b44847b379578588920cA78FbF26c0B4956C +* Salt: 0x0000000000000000000000000000000000000000000000000000000000000000 +* Contract: lib/OPOutputLookup.sol:OPOutputLookup +* Solidity: 0.8.26 +* Optimizer Runs: 200 + +Deployment Calldata + +``` +0x00000000000000000000000000000000000000000000000000000000000000006080604052348015600f57600080fd5b50611ea38061001f6000396000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c8063c81263f91161005b578063c81263f914610146578063d1d3ee3614610166578063e2dd1533146101b8578063e4ee14061461021457600080fd5b806311f2454f1461008d5780637a496563146100b6578063bab2c5ef146100d7578063babba784146100f7575b600080fd5b6100a061009b3660046117e9565b610227565b6040516100ad9190611824565b60405180910390f35b6100c96100c436600461185b565b610259565b6040516100ad929190611890565b6100ea6100e536600461185b565b61028c565b6040516100ad9190611905565b61010a6101053660046117e9565b61039c565b6040805194855263ffffffff90931660208501526001600160401b03909116918301919091526001600160a01b031660608201526080016100ad565b61015961015436600461193c565b6103c0565b6040516100ad9190611959565b610179610174366004611979565b6104cc565b6040805195865260208601949094526001600160401b039092169284019290925260608301919091526001600160a01b0316608082015260a0016100ad565b6101cb6101c636600461185b565b6104f5565b6040805196875260208701959095526001600160401b039093169385019390935260608401526001600160a01b03909116608083015263ffffffff1660a082015260c0016100ad565b61010a6102223660046117e9565b61051f565b604080516060810182526000808252602082018190529181019190915261025085858585610531565b95945050505050565b604080516060810182526000808252602082018190529181018290526102808585856106a9565b91509150935093915050565b6040805160808101825260008082526020820181905291810182905260608101919091526102b9846103c0565b819060018111156102cc576102cc6118cd565b908160018111156102df576102df6118cd565b9052506001815160018111156102f7576102f76118cd565b0361032a57600080600061030c8787876104f5565b50506020880193909352506060860152604085015250610395915050565b60008151600181111561033f5761033f6118cd565b0361037c57600080610352868686610259565b6020850191909152805160608501526040908101516001600160801b031690840152506103959050565b604051636dfa9d6760e11b815260040160405180910390fd5b9392505050565b6000806000806103ae88888888610a4c565b929b919a509850909650945050505050565b6000816001600160a01b031663f2b4e6176040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801561041c575060408051601f3d908101601f19168201909252610419918101906119bf565b60015b1561043b576001600160a01b038116156104395750600192915050565b505b816001600160a01b0316639b5f694a6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015610495575060408051601f3d908101601f19168201909252610492918101906119bf565b60015b1561037c576001600160a01b038116156104b25750600092915050565b50604051636dfa9d6760e11b815260040160405180910390fd5b60008060008060006104e089898989610c36565b94509450945094509450945094509450945094565b60008060008060008061050989898961102a565b949e939d50919b50995097509095509350505050565b6000806000806103ae888888886110b9565b604080516060810182526000808252602082018190529181018290529061055786611187565b60405163a25ae55760e01b8152600481018790529091506000906001600160a01b0383169063a25ae55790602401606060405180830381865afa1580156105a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105c69190611a5f565b90508481602001516001600160801b0316426105e29190611adf565b1015610630578581602001516001600160801b0316426106029190611adf565b6040516328711f9f60e01b815260048101929092526024820152604481018690526064015b60405180910390fd5b60008411801561065757508381602001516001600160801b0316426106559190611adf565b115b1561069f578581602001516001600160801b0316426106769190611adf565b60405163107b0e1960e01b81526004810192909252602482015260448101859052606401610627565b9695505050505050565b6040805160608101825260008082526020820181905291810182905260006106d086611187565b9050600080826001600160a01b03166369f16eec6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610713573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107379190611af2565b905060006107458842611adf565b90505b81831161096b5760405163a25ae55760e01b8152600481018490526000906001600160a01b0386169063a25ae55790602401606060405180830381865afa158015610797573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107bb9190611a5f565b602001516001600160801b031690506000856001600160a01b031663a25ae557856040518263ffffffff1660e01b81526004016107fa91815260200190565b606060405180830381865afa158015610817573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061083b9190611a5f565b602001516001600160801b03169050828211156108665761085d600186611adf565b9350505061096b565b6000828211156108b15761087a8383611adf565b6108848787611adf565b61088e8587611adf565b6108989190611b0b565b6108a29190611b22565b6108ac9087611b44565b6108b3565b855b9050848111156108c05750835b60405163a25ae55760e01b8152600481018290526000906001600160a01b0389169063a25ae55790602401606060405180830381865afa158015610908573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061092c9190611a5f565b602001516001600160801b031690508481116109545761094d826001611b44565b9650610962565b61095f600183611adf565b95505b50505050610748565b60405163a25ae55760e01b8152600481018390526000906001600160a01b0386169063a25ae55790602401606060405180830381865afa1580156109b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109d79190611a5f565b9050428882602001516001600160801b03166109f39190611b44565b1015610a3c578281602001516001600160801b031642610a139190611adf565b60405163107b0e1960e01b81526004810192909252602482015260448101899052606401610627565b9199919850909650505050505050565b6000806000806000610a5d89611232565b604051632ee2a87f60e21b8152600481018a90529091506000906001600160a01b0383169063bb8aa1fc90602401606060405180830381865afa158015610aa8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610acc9190611b6e565b809550819350829750505050610b40836001600160a01b031663bcef3b556040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b3d9190611af2565b90565b95506001600160401b038116935087610b598542611adf565b1015610b9c5788610b736001600160401b03861642611adf565b6040516366460f9d60e01b81526004810192909252602482015260448101899052606401610627565b600087118015610bbd575086610bbb6001600160401b03861642611adf565b115b15610bff5788610bd66001600160401b03861642611adf565b604051631fc476cf60e21b81526004810192909252602482015260448101889052606401610627565b610c08836112d2565b15610c29576040516336834a3160e21b8152600481018a9052602401610627565b5050945094509450949050565b60008080808080610c478842611adf565b90506000610c548b611232565b90506000610c628284611359565b60405163254bd68360e01b815263ffffffff8d16600482015260248101829052600160448201529091506000906001600160a01b0384169063254bd68390606401600060405180830381865afa158015610cc0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ce89190810190611bb7565b90508051600003610d0f5760405163d13b267760e01b8152600481018c9052602401610627565b6000610d5482600081518110610d2757610d27611d68565b60200260200101516020015160e081901c9160a082901c6001600160401b0316916001600160a01b031690565b92505050610d61816112d2565b15610e605781600081518110610d7957610d79611d68565b602002602001015160000151600003610da85760405163d13b267760e01b8152600481018d9052602401610627565b836001600160a01b031663254bd6838e600185600081518110610dcd57610dcd611d68565b602002602001015160000151610de39190611adf565b6040516001600160e01b031960e085901b16815263ffffffff929092166004830152602482015260016044820152606401600060405180830381865afa158015610e31573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610e599190810190611bb7565b9150610e66565b50610e6c565b50610d0f565b80600081518110610e7f57610e7f611d68565b6020026020010151600001519850610eb281600081518110610ea357610ea3611d68565b60200260200101516060015190565b9750610ee281600081518110610eca57610eca611d68565b6020026020010151604001516001600160401b031690565b965060008a118015610f05575042610f038b6001600160401b038a16611b44565b105b15610f475788610f1e6001600160401b03891642611adf565b604051631fc476cf60e21b815260048101929092526024820152604481018b9052606401610627565b604051632ee2a87f60e21b8152600481018a90526001600160a01b0384169063bb8aa1fc90602401606060405180830381865afa158015610f8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fb09190611b6e565b909150905080955050846001600160a01b0316638b85902b6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015611013575060408051601f3d908101601f1916820190925261101091810190611af2565b60015b1561101b5795505b50505050945094509450945094565b600080600080600080886001600160a01b0316633c9f397c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611071573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110959190611d7e565b90506110a389828a8a610c36565b939d929c50909a50985090965090945092505050565b6000806000806000886001600160a01b0316633c9f397c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110ff573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111239190611d7e565b905061113189898989610a4c565b9297509095509350915063ffffffff8085169082161461117b576040516323fa115960e21b81526004810189905263ffffffff808316602483015285166044820152606401610627565b50945094509450949050565b6000816001600160a01b0316639b5f694a6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156111e3575060408051601f3d908101601f191682019092526111e0918101906119bf565b60015b61120057604051638b4df23f60e01b815260040160405180910390fd5b6001600160a01b03811661122757604051638b4df23f60e01b815260040160405180910390fd5b92915050565b919050565b6000816001600160a01b031663f2b4e6176040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801561128e575060408051601f3d908101601f1916820190925261128b918101906119bf565b60015b6112ab57604051635a23942360e11b815260040160405180910390fd5b6001600160a01b03811661122757604051635a23942360e11b815260040160405180910390fd5b60006001826001600160a01b031663200d2ed26040518163ffffffff1660e01b8152600401602060405180830381865afa158015611314573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113389190611d9b565b6002811115611349576113496118cd565b148061122757506112278261163b565b6000806000905060006001856001600160a01b0316634d1975b46040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113c69190611af2565b6113d09190611adf565b90505b80821161163357604051632ee2a87f60e21b8152600481018390526000906001600160a01b0387169063bb8aa1fc90602401606060405180830381865afa158015611422573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114469190611b6e565b50604051632ee2a87f60e21b815260048101859052909250600091506001600160a01b0388169063bb8aa1fc90602401606060405180830381865afa158015611493573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114b79190611b6e565b50915050856114cc836001600160401b031690565b6001600160401b031611156114f1576114e6600185611adf565b945050505050611227565b60006001600160401b0383811690831611156115665761151d6001600160401b03848116908416611dbc565b6001600160401b03166115308686611adf565b6115436001600160401b0386168a611adf565b61154d9190611b0b565b6115579190611b22565b6115619086611b44565b611568565b845b9050838111156115755750825b604051632ee2a87f60e21b8152600481018290526000906001600160a01b038a169063bb8aa1fc90602401606060405180830381865afa1580156115bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115e19190611b6e565b5091505060006115f7826001600160401b031690565b905088816001600160401b03161161161b57611614836001611b44565b9650611629565b611626600184611adf565b95505b50505050506113d3565b949350505050565b60006002826001600160a01b031663200d2ed26040518163ffffffff1660e01b8152600401602060405180830381865afa15801561167d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116a19190611d9b565b60028111156116b2576116b26118cd565b036116bf57506000919050565b6001826001600160a01b0316638980e0cc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156116ff573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117239190611af2565b111561173157506001919050565b6040516331bc0c2360e21b8152600060048201819052906001600160a01b0384169063c6f0308c9060240160e060405180830381865afa158015611779573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061179d9190611ddb565b505050505091505060006001600160a01b0316816001600160a01b0316146117c85750600192915050565b50600092915050565b6001600160a01b03811681146117e657600080fd5b50565b600080600080608085870312156117ff57600080fd5b843561180a816117d1565b966020860135965060408601359560600135945092505050565b606081016112278284805182526001600160801b0360208201511660208301526001600160801b0360408201511660408301525050565b60008060006060848603121561187057600080fd5b833561187b816117d1565b95602085013595506040909401359392505050565b828152608081016103956020830184805182526001600160801b0360208201511660208301526001600160801b0360408201511660408301525050565b634e487b7160e01b600052602160045260246000fd5b6002811061190157634e487b7160e01b600052602160045260246000fd5b9052565b60006080820190506119188284516118e3565b60208301516020830152604083015160408301526060830151606083015292915050565b60006020828403121561194e57600080fd5b8135610395816117d1565b6020810161122782846118e3565b63ffffffff811681146117e657600080fd5b6000806000806080858703121561198f57600080fd5b843561199a816117d1565b935060208501356119aa81611967565b93969395505050506040820135916060013590565b6000602082840312156119d157600080fd5b8151610395816117d1565b634e487b7160e01b600052604160045260246000fd5b60405160a081016001600160401b0381118282101715611a1457611a146119dc565b60405290565b604051601f8201601f191681016001600160401b0381118282101715611a4257611a426119dc565b604052919050565b6001600160801b03811681146117e657600080fd5b60006060828403128015611a7257600080fd5b50604051606081016001600160401b0381118282101715611a9557611a956119dc565b604052825181526020830151611aaa81611a4a565b60208201526040830151611abd81611a4a565b60408201529392505050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561122757611227611ac9565b600060208284031215611b0457600080fd5b5051919050565b808202811582820484141761122757611227611ac9565b600082611b3f57634e487b7160e01b600052601260045260246000fd5b500490565b8082018082111561122757611227611ac9565b80516001600160401b038116811461122d57600080fd5b600080600060608486031215611b8357600080fd5b8351611b8e81611967565b9250611b9c60208501611b57565b91506040840151611bac816117d1565b809150509250925092565b600060208284031215611bc957600080fd5b81516001600160401b03811115611bdf57600080fd5b8201601f81018413611bf057600080fd5b80516001600160401b03811115611c0957611c096119dc565b8060051b611c1960208201611a1a565b91825260208184018101929081019087841115611c3557600080fd5b6020850192505b83831015611d5d5782516001600160401b03811115611c5a57600080fd5b850160a0818a03601f19011215611c7057600080fd5b611c786119f2565b6020828101518252604083015190820152611c9560608301611b57565b60408201526080820151606082015260a08201516001600160401b03811115611cbd57600080fd5b60208184010192505089601f830112611cd557600080fd5b81516001600160401b03811115611cee57611cee6119dc565b611d01601f8201601f1916602001611a1a565b8181528b6020838601011115611d1657600080fd5b60005b82811015611d3557602081860181015183830182015201611d19565b5060006020838301015280608084015250508084525050602082019150602083019250611c3c565b979650505050505050565b634e487b7160e01b600052603260045260246000fd5b600060208284031215611d9057600080fd5b815161039581611967565b600060208284031215611dad57600080fd5b81516003811061039557600080fd5b6001600160401b03828116828216039081111561122757611227611ac9565b600080600080600080600060e0888a031215611df657600080fd5b8751611e0181611967565b6020890151909750611e12816117d1565b6040890151909650611e23816117d1565b6060890151909550611e3481611a4a565b608089015160a08a01519195509350611e4c81611a4a565b60c0890151909250611e5d81611a4a565b809150509295989194975092955056fea264697066735822122013c9ca5c68c37024a9b4368e048a2c1ff607f615fdb170ac9d3267f512232e3664736f6c634300081a0033 +``` + ## Testing gateway ``` diff --git a/op-verifier/contracts/OPVerifier.sol b/op-verifier/contracts/OPVerifier.sol index 0c2b5c71..6f4257e1 100644 --- a/op-verifier/contracts/OPVerifier.sol +++ b/op-verifier/contracts/OPVerifier.sol @@ -1,44 +1,98 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.17; +pragma solidity ^0.8.15; -import { IEVMVerifier } from "@ensdomains/evm-verifier/contracts/IEVMVerifier.sol"; -import { RLPReader } from "@eth-optimism/contracts-bedrock/src/libraries/rlp/RLPReader.sol"; -import { StateProof, EVMProofHelper } from "@ensdomains/evm-verifier/contracts/EVMProofHelper.sol"; -import { Types } from "@eth-optimism/contracts-bedrock/src/libraries/Types.sol"; -import { Hashing } from "@eth-optimism/contracts-bedrock/src/libraries/Hashing.sol"; +import {IEVMVerifier} from '@ensdomains/evm-verifier/contracts/IEVMVerifier.sol'; +import {StateProof, EVMProofHelper} from '@ensdomains/evm-verifier/contracts/EVMProofHelper.sol'; +import {DisputeGameLookup, L2OutputOracleLookup, IOptimismPortalOutputRoot, OPWitnessProofType} from './lib/OPOutputLookup.sol'; import {MerkleTrieProofHelper} from '@ensdomains/evm-verifier/contracts/MerkleTrieProofHelper.sol'; +import {Hashing} from '@eth-optimism/contracts-bedrock/src/libraries/Hashing.sol'; +import {Types} from '@eth-optimism/contracts-bedrock/src/libraries/Types.sol'; struct OPWitnessData { - uint256 l2OutputIndex; + OPWitnessProofType proofType; + uint256 index; Types.OutputRootProof outputRootProof; } -interface IL2OutputOracle { - function getL2Output(uint256 _l2OutputIndex) external view returns (Types.OutputProposal memory); -} - contract OPVerifier is IEVMVerifier { - error OutputRootMismatch(uint256 l2OutputIndex, bytes32 expected, bytes32 actual); + error OutputRootMismatch( + OPWitnessProofType proofType, + uint256 index, + bytes32 expected, + bytes32 actual + ); + + IOptimismPortalOutputRoot public immutable optimismPortal; + uint256 public immutable minAge; + uint256 public immutable maxAge; - IL2OutputOracle public opOracle; string[] _gatewayURLs; - constructor(string[] memory urls, address outputOracle) { + constructor( + string[] memory urls, + address optimismPortalAddress, + uint256 minimumAge, + uint256 maximumAge + ) { _gatewayURLs = urls; - opOracle = IL2OutputOracle(outputOracle); + optimismPortal = IOptimismPortalOutputRoot(optimismPortalAddress); + minAge = minimumAge; + maxAge = maximumAge; } - function gatewayURLs() external view returns(string[] memory) { + function gatewayURLs() external view returns (string[] memory) { return _gatewayURLs; } - function getStorageValues(address target, bytes32[] memory commands, bytes[] memory constants, bytes memory proof) external view returns(bytes[] memory values) { - (OPWitnessData memory opData, StateProof memory stateProof) = abi.decode(proof, (OPWitnessData, StateProof)); - Types.OutputProposal memory l2out = opOracle.getL2Output(opData.l2OutputIndex); - bytes32 expectedRoot = Hashing.hashOutputRootProof(opData.outputRootProof); - if(l2out.outputRoot != expectedRoot) { - revert OutputRootMismatch(opData.l2OutputIndex, expectedRoot, l2out.outputRoot); + function getL2OracleOutput(uint256 index) internal view returns (bytes32) { + return + L2OutputOracleLookup + .getL2Output(optimismPortal, index, minAge, maxAge) + .outputRoot; + } + + function getDisputeGameOutput( + uint256 index + ) internal view returns (bytes32) { + (bytes32 outputRoot, , , ) = DisputeGameLookup.getRespectedDisputeGame( + optimismPortal, + index, + minAge, + maxAge + ); + + return outputRoot; + } + + function getStorageValues( + address target, + bytes32[] memory commands, + bytes[] memory constants, + bytes memory proof + ) external view returns (bytes[] memory values) { + (OPWitnessData memory opData, StateProof memory stateProof) = abi + .decode(proof, (OPWitnessData, StateProof)); + bytes32 expectedRoot = Hashing.hashOutputRootProof( + opData.outputRootProof + ); + + bytes32 outputRoot; + + if (opData.proofType == OPWitnessProofType.DisputeGame) { + outputRoot = getDisputeGameOutput(opData.index); + } else if (opData.proofType == OPWitnessProofType.L2OutputOracle) { + outputRoot = getL2OracleOutput(opData.index); } + + if (outputRoot != expectedRoot) { + revert OutputRootMismatch( + opData.proofType, + opData.index, + expectedRoot, + outputRoot + ); + } + bytes32 storageRoot = MerkleTrieProofHelper.getStorageRoot(opData.outputRootProof.stateRoot, target, stateProof.stateTrieWitness); return EVMProofHelper.getStorageValues(target, MerkleTrieProofHelper.getTrieProof, commands, constants, storageRoot, stateProof.storageProofs); } diff --git a/op-verifier/contracts/lib/DisputeGameLookup.sol b/op-verifier/contracts/lib/DisputeGameLookup.sol new file mode 100644 index 00000000..c8a9fdce --- /dev/null +++ b/op-verifier/contracts/lib/DisputeGameLookup.sol @@ -0,0 +1,406 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import './dispute/interfaces/IFaultDisputeGame.sol'; +import {IOptimismPortalOutputRoot, IDisputeGameFactory} from './IOptimismPortalOutputRoot.sol'; +import { GameStatus, Timestamp } from "./dispute/lib/Types.sol"; + +interface IChallengingDisputeGame is IFaultDisputeGame { + function claimData( + uint256 index + ) + external + view + returns ( + uint32 parentIndex, + address counteredBy, + address claimant, + uint128 bond, + Claim claim, + Position position, + Clock clock + ); + + function claimDataLen() external view returns (uint256 len_); +} + +/** + * @title DisputeGameLookup + * @dev Library for querying dispute games in the Optimism portal. + */ +library DisputeGameLookup { + /** + * @dev Emitted when the game type does not match the expected type. + * @param disputeGameIndex Index of the dispute game. + * @param expected Expected game type. + * @param actual Actual game type. + */ + error GameTypeMismatch( + uint256 disputeGameIndex, + GameType expected, + GameType actual + ); + + /** + * @dev Emitted when the dispute game is already challenged or challenging. + * @param disputeGameIndex Index of the dispute game. + */ + error GameInvalid(uint256 disputeGameIndex); + + /** + * @dev Emitted when the dispute game is too early to be challenged. + * @param disputeGameIndex Index of the dispute game. + * @param age Current age of the game. + * @param minAge Minimum age required to challenge the game. + */ + error GameTooEarly(uint256 disputeGameIndex, uint256 age, uint256 minAge); + + /** + * @dev Emitted when the dispute game is expired. + * @param disputeGameIndex Index of the dispute game. + * @param age Current age of the game. + * @param maxAge Maximum age allowed to challenge the game. + */ + error GameExpired(uint256 disputeGameIndex, uint256 age, uint256 maxAge); + + /** + * @dev Emitted when no dispute game is found within the specified minimum age. + * @param minAge Minimum age required. + */ + error GameNotFound(uint256 minAge); + + /** + * @dev Emitted when the dispute game is not enabled. + */ + error DisputeGameNotEnabled(); + + /** + * @notice Internal function to get the dispute game factory from the optimism portal. + * @param optimismPortal The Optimism portal output root contract. + * @return factory The dispute game factory. + */ + function _disputeGameFactory( + IOptimismPortalOutputRoot optimismPortal + ) internal view returns (IDisputeGameFactory) { + try optimismPortal.disputeGameFactory() returns ( + IDisputeGameFactory factory + ) { + if (address(factory) == address(0)) { + revert DisputeGameNotEnabled(); + } + + return factory; + } catch { + revert DisputeGameNotEnabled(); + } + } + + /** + * @notice Internal function to check if the dispute game is challenging. + * @param proxy Dispute Game Proxy to check + * @return invalid Is the game being challenged? + */ + function _isGameChallenging( + IChallengingDisputeGame proxy + ) internal view returns (bool) { + // If the game is finalized, we ignore the challenging status + if (proxy.status() == GameStatus.DEFENDER_WINS) return false; + + // If claimData length is greater than 1, the game is challenging + if (proxy.claimDataLen() > 1) { + return true; + } + + // If root claim is countered by someone then the game is challenging + (, address counteredBy, , , , , ) = proxy.claimData(0); + if (counteredBy != address(0)) return true; + + return false; + } + + /** + * @notice Internal function to check if the dispute game has already been challenged or is challenging. + * @param proxy Dispute Game Proxy to check + * @return invalid Has the game already been challenged or is it still challenging? + */ + function _isGameInvalid(IDisputeGame proxy) internal view returns (bool) { + return + proxy.status() == GameStatus.CHALLENGER_WINS || + _isGameChallenging(IChallengingDisputeGame(address(proxy))); + } + + /** + * @notice Retrieves the dispute game at the specified index. + * @param optimismPortal The Optimism portal output root contract. + * @param index The index of the dispute game. + * @param minAge The minimum age required to challenge the game. + * @param maxAge The maximum age allowed to challenge the game. + * @return outputRoot The root claim of the dispute game. + * @return gameType The type of the dispute game. + * @return gameCreationTime The creation time of the dispute game. + * @return proxy The dispute game proxy. + */ + function getDisputeGame( + IOptimismPortalOutputRoot optimismPortal, + uint256 index, + uint256 minAge, + uint256 maxAge + ) + internal + view + returns ( + bytes32 outputRoot, + GameType gameType, + uint64 gameCreationTime, + IDisputeGame proxy + ) + { + IDisputeGameFactory disputeGameFactory = _disputeGameFactory( + optimismPortal + ); + + // Get dispute game at index + Timestamp gameCreationTimeRaw; + (gameType, gameCreationTimeRaw, proxy) = disputeGameFactory.gameAtIndex( + index + ); + outputRoot = proxy.rootClaim().raw(); + + // Unwrap gameCreationTime to uint64 + gameCreationTime = gameCreationTimeRaw.raw(); + + // Wait for challenger to challenge the dispute game + if (block.timestamp - gameCreationTime < minAge) { + revert GameTooEarly( + index, + block.timestamp - gameCreationTime, + minAge + ); + } + + // Reject dispute game that has been expired + if (maxAge > 0 && block.timestamp - gameCreationTime > maxAge) { + revert GameExpired( + index, + block.timestamp - gameCreationTime, + maxAge + ); + } + + // Revert if the game is challenged or challenging + if (_isGameInvalid(proxy)) { + revert GameInvalid(index); + } + } + + /** + * @notice Retrieves the dispute game that is respected for L2 withdrawal. + * @param optimismPortal The Optimism portal output root contract. + * @param index The index of the dispute game. + * @param minAge The minimum age required to challenge the game. + * @param maxAge The maximum age allowed to challenge the game. + * @return outputRoot The root claim of the dispute game. + * @return gameType The type of the respected dispute game. + * @return gameCreationTime The creation time of the dispute game. + * @return proxy The dispute game proxy. + */ + function getRespectedDisputeGame( + IOptimismPortalOutputRoot optimismPortal, + uint256 index, + uint256 minAge, + uint256 maxAge + ) + internal + view + returns ( + bytes32 outputRoot, + GameType gameType, + uint64 gameCreationTime, + IDisputeGame proxy + ) + { + // Get gameType used for L2 withdrawal + GameType respectedGameType = optimismPortal.respectedGameType(); + + // Get dispute game output and game type + (outputRoot, gameType, gameCreationTime, proxy) = getDisputeGame( + optimismPortal, + index, + minAge, + maxAge + ); + + // Revert if gameType is not the one used for L2 withdrawal + if (gameType.raw() != respectedGameType.raw()) { + revert GameTypeMismatch(index, respectedGameType, gameType); + } + } + + /** + * @notice Finds the start index for searching based on the maximum timestamp. + * @param disputeGameFactory The dispute game factory. + * @param maxTimestamp The maximum timestamp to search. + * @return The start index. + */ + function _findSearchStart( + IDisputeGameFactory disputeGameFactory, + uint256 maxTimestamp + ) internal view returns (uint256) { + uint256 lo = 0; + uint256 hi = disputeGameFactory.gameCount() - 1; + + while (lo <= hi) { + (, Timestamp _timestampLo, ) = disputeGameFactory.gameAtIndex(lo); + (, Timestamp _timestampHi, ) = disputeGameFactory.gameAtIndex(hi); + + // If lower bound exceed max timestamp, return previous mid (lo - 1) + if (_timestampLo.raw() > maxTimestamp) return lo - 1; + + // Interpolation search + uint256 mid = _timestampHi.raw() <= _timestampLo.raw() + ? lo + : lo + + ((maxTimestamp - _timestampLo.raw()) * (hi - lo)) / + (_timestampHi.raw() - _timestampLo.raw()); + + // Rounding error + if (mid > hi) { + mid = hi; + } + + (, Timestamp _timestampRaw, ) = disputeGameFactory.gameAtIndex(mid); + + // Unwrap gameCreationTime to uint64 + uint64 _timestamp = _timestampRaw.raw(); + + if (_timestamp <= maxTimestamp) { + lo = mid + 1; + } else { + hi = mid - 1; + } + } + + return hi; + } + + /** + * @notice Retrieves the latest dispute game of a specific type. + * @param optimismPortal The Optimism portal output root contract. + * @param gameType The type of the dispute game. + * @param minAge The minimum age required to challenge the game. + * @param maxAge The maximum age allowed to challenge the game. + * @return disputeGameIndex The index of the dispute game. + * @return outputRoot The root claim of the dispute game. + * @return gameCreationTime The creation time of the dispute game. + * @return blockNumber The block number of the L2 state. + * @return proxy The dispute game proxy. + */ + function getLatestDisputeGame( + IOptimismPortalOutputRoot optimismPortal, + GameType gameType, + uint256 minAge, + uint256 maxAge + ) + internal + view + returns ( + uint256 disputeGameIndex, + bytes32 outputRoot, + uint64 gameCreationTime, + uint256 blockNumber, + IDisputeGame proxy + ) + { + uint256 maxTimestamp = block.timestamp - minAge; + + IDisputeGameFactory disputeGameFactory = _disputeGameFactory( + optimismPortal + ); + + uint256 start = _findSearchStart(disputeGameFactory, maxTimestamp); + + IDisputeGameFactory.GameSearchResult[] memory games = disputeGameFactory + .findLatestGames(gameType, start, 1); + + if (games.length == 0) { + revert GameNotFound(minAge); + } + + // In case of an invalid game is found + while (true) { + (, , address p) = games[0].metadata.unpack(); + if (_isGameInvalid(IDisputeGame(p))) { + if (games[0].index == 0) { + revert GameNotFound(minAge); + } + games = disputeGameFactory.findLatestGames( + gameType, + games[0].index - 1, + 1 + ); + } else { + break; + } + } + + disputeGameIndex = games[0].index; + outputRoot = games[0].rootClaim.raw(); + gameCreationTime = games[0].timestamp.raw(); + + if (maxAge > 0 && gameCreationTime + maxAge < block.timestamp) { + revert GameExpired( + disputeGameIndex, + block.timestamp - gameCreationTime, + maxAge + ); + } + + (, , proxy) = disputeGameFactory.gameAtIndex(disputeGameIndex); + + try IFaultDisputeGame(address(proxy)).l2BlockNumber() returns ( + uint256 l2BlockNumber + ) { + blockNumber = l2BlockNumber; + } catch {} + } + + /** + * @notice Retrieves the latest respected dispute game for L2 withdrawal. + * @param optimismPortal The Optimism portal output root contract. + * @param minAge The minimum age required to challenge the game. + * @param maxAge The maximum age allowed to challenge the game. + * @return disputeGameIndex The index of the dispute game. + * @return outputRoot The root claim of the dispute game. + * @return gameCreationTime The creation time of the dispute game. + * @return blockNumber The block number of the L2 state. + * @return proxy The dispute game proxy. + * @return gameType The type of the respected dispute game. + */ + function getLatestRespectedDisputeGame( + IOptimismPortalOutputRoot optimismPortal, + uint256 minAge, + uint256 maxAge + ) + internal + view + returns ( + uint256 disputeGameIndex, + bytes32 outputRoot, + uint64 gameCreationTime, + uint256 blockNumber, + IDisputeGame proxy, + GameType gameType + ) + { + // Get gameType used for L2 withdrawal + gameType = optimismPortal.respectedGameType(); + + ( + disputeGameIndex, + outputRoot, + gameCreationTime, + blockNumber, + proxy + ) = getLatestDisputeGame(optimismPortal, gameType, minAge, maxAge); + } +} diff --git a/op-verifier/contracts/lib/IOptimismPortalOutputRoot.sol b/op-verifier/contracts/lib/IOptimismPortalOutputRoot.sol new file mode 100644 index 00000000..bba4e5a8 --- /dev/null +++ b/op-verifier/contracts/lib/IOptimismPortalOutputRoot.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import { IDisputeGameFactory, GameType } from "./dispute/interfaces/IDisputeGameFactory.sol"; +import { Types } from '@eth-optimism/contracts-bedrock/src/libraries/Types.sol'; + +interface IL2OutputOracle { + function getL2Output( + uint256 _l2OutputIndex + ) external view returns (Types.OutputProposal memory); + + function latestOutputIndex() external view returns (uint256); +} + +interface IOptimismPortalOutputRoot { + function l2Oracle() external view returns (IL2OutputOracle); + + function disputeGameFactory() external view returns (IDisputeGameFactory); + + function respectedGameType() external view returns (GameType); +} \ No newline at end of file diff --git a/op-verifier/contracts/lib/L2OutputOracleLookup.sol b/op-verifier/contracts/lib/L2OutputOracleLookup.sol new file mode 100644 index 00000000..99bf272d --- /dev/null +++ b/op-verifier/contracts/lib/L2OutputOracleLookup.sol @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {IL2OutputOracle, IOptimismPortalOutputRoot, Types} from "./IOptimismPortalOutputRoot.sol"; + +/** + * @title L2OutputOracleLookup + * @dev Library for querying L2 output oracles in the Optimism portal. + */ +library L2OutputOracleLookup { + /** + * @dev Emitted when the L2 output is expired. + * @param l2OutputIndex Index of the L2 output. + * @param age Current age of the output. + * @param maxAge Maximum age allowed for the output. + */ + error OutputExpired(uint256 l2OutputIndex, uint256 age, uint256 maxAge); + + /** + * @dev Emitted when the L2 output is too early to be challenged. + * @param l2OutputIndex Index of the L2 output. + * @param age Current age of the output. + * @param minAge Minimum age required to challenge the output. + */ + error OutputTooEarly(uint256 l2OutputIndex, uint256 age, uint256 minAge); + + /** + * @dev Emitted when the L2 output oracle is deprecated. + */ + error L2OutputOracleDeprecated(); + + /** + * @notice Internal function to get the L2 output oracle from the Optimism portal. + * @param optimismPortal The Optimism portal output root contract. + * @return oracle The L2 output oracle. + */ + function _l2OutputOracle( + IOptimismPortalOutputRoot optimismPortal + ) internal view returns (IL2OutputOracle) { + try optimismPortal.l2Oracle() returns (IL2OutputOracle oracle) { + if (address(oracle) == address(0)) { + revert L2OutputOracleDeprecated(); + } + + return oracle; + } catch { + revert L2OutputOracleDeprecated(); + } + } + + /** + * @notice Retrieves the latest L2 output that meets the specified age criteria. + * @param optimismPortal The Optimism portal output root contract. + * @param minAge The minimum age required for the output. + * @param maxAge The maximum age allowed for the output. + * @return index The index of the latest L2 output. + * @return The latest L2 output proposal. + */ + function getLatestL2Output( + IOptimismPortalOutputRoot optimismPortal, + uint256 minAge, + uint256 maxAge + ) internal view returns (uint256, Types.OutputProposal memory) { + IL2OutputOracle oracle = _l2OutputOracle(optimismPortal); + + uint256 lo = 0; + uint256 hi = oracle.latestOutputIndex(); + + uint256 maxTimestamp = block.timestamp - minAge; + + while (lo <= hi) { + uint256 timestampLo = oracle.getL2Output(lo).timestamp; + uint256 timestampHi = oracle.getL2Output(hi).timestamp; + + // If lower bound exceed max timestamp, return previous mid (lo - 1) + if (timestampLo > maxTimestamp) { + hi = lo - 1; + break; + } + + // Interpolation search + uint256 mid = timestampHi <= timestampLo + ? lo + : lo + + ((maxTimestamp - timestampLo) * (hi - lo)) / + (timestampHi - timestampLo); + + // Rounding error + if (mid > hi) { + mid = hi; + } + + uint256 timestampMid = oracle.getL2Output(mid).timestamp; + + if (timestampMid <= maxTimestamp) { + lo = mid + 1; + } else { + hi = mid - 1; + } + } + + Types.OutputProposal memory output = oracle.getL2Output(hi); + + if (output.timestamp + maxAge < block.timestamp) { + revert OutputExpired( + hi, + block.timestamp - output.timestamp, + maxAge + ); + } + + return (hi, output); + } + + /** + * @notice Retrieves the L2 output at the specified index that meets the specified age criteria. + * @param optimismPortal The Optimism portal output root contract. + * @param index The index of the L2 output. + * @param minAge The minimum age required for the output. + * @param maxAge The maximum age allowed for the output. + * @return The L2 output proposal. + */ + function getL2Output( + IOptimismPortalOutputRoot optimismPortal, + uint256 index, + uint256 minAge, + uint256 maxAge + ) internal view returns (Types.OutputProposal memory) { + IL2OutputOracle oracle = _l2OutputOracle(optimismPortal); + Types.OutputProposal memory output = oracle.getL2Output(index); + + // Wait for challenger to challenge the output + if (block.timestamp - output.timestamp < minAge) { + revert OutputTooEarly( + index, + block.timestamp - output.timestamp, + minAge + ); + } + + // Reject output that has been expired + if (maxAge > 0 && block.timestamp - output.timestamp > maxAge) { + revert OutputExpired( + index, + block.timestamp - output.timestamp, + maxAge + ); + } + + return output; + } +} diff --git a/op-verifier/contracts/lib/OPOutputLookup.sol b/op-verifier/contracts/lib/OPOutputLookup.sol new file mode 100644 index 00000000..4f21b111 --- /dev/null +++ b/op-verifier/contracts/lib/OPOutputLookup.sol @@ -0,0 +1,301 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import "./dispute/interfaces/IFaultDisputeGame.sol"; +import "./DisputeGameLookup.sol"; +import "./L2OutputOracleLookup.sol"; +import "./IOptimismPortalOutputRoot.sol"; + +// For OPVerifier ENS Gateway +enum OPWitnessProofType { + L2OutputOracle, + DisputeGame +} + +// For OPVerifier ENS Gateway +struct OPProvableBlock { + OPWitnessProofType proofType; + uint256 index; + uint256 blockNumber; + bytes32 outputRoot; +} + +/** + * @title OPOutputLookup + * @dev Contract for querying dispute games and L2 output oracles in the Optimism portal. + */ +contract OPOutputLookup { + // ======================== + // Dispute Game + // ======================== + + /** + * @notice Retrieves the dispute game at the specified index. + * @param optimismPortal The Optimism portal output root contract. + * @param index The index of the dispute game. + * @param minAge The minimum age required for the game. + * @param maxAge The maximum age allowed for the game. + * @return outputRoot The root claim of the dispute game. + * @return gameType The type of the dispute game. + * @return gameCreationTime The creation time of the dispute game. + * @return proxy The dispute game proxy. + */ + function getDisputeGame( + IOptimismPortalOutputRoot optimismPortal, + uint256 index, + uint256 minAge, + uint256 maxAge + ) + public + view + returns ( + bytes32 outputRoot, + GameType gameType, + uint64 gameCreationTime, + IDisputeGame proxy + ) + { + return + DisputeGameLookup.getDisputeGame( + optimismPortal, + index, + minAge, + maxAge + ); + } + + /** + * @notice Retrieves the respected dispute game at the specified index. + * @param optimismPortal The Optimism portal output root contract. + * @param index The index of the dispute game. + * @param minAge The minimum age required for the game. + * @param maxAge The maximum age allowed for the game. + * @return outputRoot The root claim of the dispute game. + * @return gameType The type of the respected dispute game. + * @return gameCreationTime The creation time of the dispute game. + * @return proxy The dispute game proxy. + */ + function getRespectedDisputeGame( + IOptimismPortalOutputRoot optimismPortal, + uint256 index, + uint256 minAge, + uint256 maxAge + ) + public + view + returns ( + bytes32 outputRoot, + GameType gameType, + uint64 gameCreationTime, + IDisputeGame proxy + ) + { + return + DisputeGameLookup.getRespectedDisputeGame( + optimismPortal, + index, + minAge, + maxAge + ); + } + + /** + * @notice Retrieves the latest dispute game of a specific type. + * @param optimismPortal The Optimism portal output root contract. + * @param gameType The type of the dispute game. + * @param minAge The minimum age required for the game. + * @param maxAge The maximum age allowed for the game. + * @return disputeGameIndex The index of the dispute game. + * @return outputRoot The root claim of the dispute game. + * @return gameCreationTime The creation time of the dispute game. + * @return blockNumber The block number of the L2 state. + * @return proxy The dispute game proxy. + */ + function getLatestDisputeGame( + IOptimismPortalOutputRoot optimismPortal, + GameType gameType, + uint256 minAge, + uint256 maxAge + ) + public + view + returns ( + uint256 disputeGameIndex, + bytes32 outputRoot, + uint64 gameCreationTime, + uint256 blockNumber, + IDisputeGame proxy + ) + { + return + DisputeGameLookup.getLatestDisputeGame( + optimismPortal, + gameType, + minAge, + maxAge + ); + } + + /** + * @notice Retrieves the latest respected dispute game for L2 withdrawal. + * @param optimismPortal The Optimism portal output root contract. + * @param minAge The minimum age required for the game. + * @param maxAge The maximum age allowed for the game. + * @return disputeGameIndex The index of the dispute game. + * @return outputRoot The root claim of the dispute game. + * @return gameCreationTime The creation time of the dispute game. + * @return blockNumber The block number of the L2 state. + * @return proxy The dispute game proxy. + * @return gameType The type of the respected dispute game. + */ + function getLatestRespectedDisputeGame( + IOptimismPortalOutputRoot optimismPortal, + uint256 minAge, + uint256 maxAge + ) + public + view + returns ( + uint256 disputeGameIndex, + bytes32 outputRoot, + uint64 gameCreationTime, + uint256 blockNumber, + IDisputeGame proxy, + GameType gameType + ) + { + return + DisputeGameLookup.getLatestRespectedDisputeGame( + optimismPortal, + minAge, + maxAge + ); + } + + // ======================== + // L2 Output Oracle + // ======================== + + /** + * @notice Retrieves the latest L2 output that meets the specified age criteria. + * @param optimismPortal The Optimism portal output root contract. + * @param minAge The minimum age required for the output. + * @param maxAge The maximum age allowed for the output. + * @return index The index of the latest L2 output. + * @return The latest L2 output proposal. + */ + function getLatestL2Output( + IOptimismPortalOutputRoot optimismPortal, + uint256 minAge, + uint256 maxAge + ) public view returns (uint256 index, Types.OutputProposal memory) { + return + L2OutputOracleLookup.getLatestL2Output( + optimismPortal, + minAge, + maxAge + ); + } + + /** + * @notice Retrieves the L2 output at the specified index that meets the specified age criteria. + * @param optimismPortal The Optimism portal output root contract. + * @param index The index of the L2 output. + * @param minAge The minimum age required for the output. + * @param maxAge The maximum age allowed for the output. + * @return The L2 output proposal. + */ + function getL2Output( + IOptimismPortalOutputRoot optimismPortal, + uint256 index, + uint256 minAge, + uint256 maxAge + ) public view returns (Types.OutputProposal memory) { + return + L2OutputOracleLookup.getL2Output( + optimismPortal, + index, + minAge, + maxAge + ); + } + + // ======================== + // ENS Gateway + // ======================== + + /** + * @dev Emitted when the proof type is unknown. + */ + error UnknownProofType(); + + /** + * @notice Retrieves the proof type used by the Optimism portal. + * @param optimismPortal The Optimism portal output root contract. + * @return The proof type used by the Optimism portal. + */ + function getProofType( + IOptimismPortalOutputRoot optimismPortal + ) public view returns (OPWitnessProofType) { + try optimismPortal.disputeGameFactory() returns ( + IDisputeGameFactory factory + ) { + if (address(factory) != address(0)) { + return OPWitnessProofType.DisputeGame; + } + } catch {} + + try optimismPortal.l2Oracle() returns (IL2OutputOracle oracle) { + if (address(oracle) != address(0)) { + return OPWitnessProofType.L2OutputOracle; + } + } catch {} + + revert UnknownProofType(); + } + + /** + * @notice Retrieves the OP provable block that meets the specified age criteria. + * @param optimismPortal The Optimism portal output root contract. + * @param minAge The minimum age required for the proof. + * @param maxAge The maximum age allowed for the proof. + * @return result The OP provable block for ENS OP Gateway. + */ + function getOPProvableBlock( + IOptimismPortalOutputRoot optimismPortal, + uint256 minAge, + uint256 maxAge + ) public view returns (OPProvableBlock memory result) { + result.proofType = getProofType(optimismPortal); + + if (result.proofType == OPWitnessProofType.DisputeGame) { + ( + uint256 disputeGameIndex, + bytes32 outputRoot, + , + uint256 blockNumber, + , + + ) = getLatestRespectedDisputeGame(optimismPortal, minAge, maxAge); + + result.index = disputeGameIndex; + result.outputRoot = outputRoot; + result.blockNumber = blockNumber; + + return result; + } else if (result.proofType == OPWitnessProofType.L2OutputOracle) { + ( + uint256 index, + Types.OutputProposal memory output + ) = getLatestL2Output(optimismPortal, minAge, maxAge); + + result.index = index; + result.outputRoot = output.outputRoot; + result.blockNumber = output.l2BlockNumber; + + return result; + } + + revert UnknownProofType(); + } +} diff --git a/op-verifier/contracts/lib/dispute/interfaces/IAnchorStateRegistry.sol b/op-verifier/contracts/lib/dispute/interfaces/IAnchorStateRegistry.sol new file mode 100644 index 00000000..a44f05f8 --- /dev/null +++ b/op-verifier/contracts/lib/dispute/interfaces/IAnchorStateRegistry.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import { IFaultDisputeGame } from "./IFaultDisputeGame.sol"; +import { IDisputeGameFactory } from "./IDisputeGameFactory.sol"; +import { ISuperchainConfig } from "../lib/ISuperchainConfig.sol"; +import { GameType, Hash, OutputRoot } from "../lib/Types.sol"; + +interface IAnchorStateRegistry { + struct StartingAnchorRoot { + GameType gameType; + OutputRoot outputRoot; + } + + error InvalidGameStatus(); + error Unauthorized(); + error UnregisteredGame(); + + event Initialized(uint8 version); + + function anchors(GameType) external view returns (Hash root, uint256 l2BlockNumber); // nosemgrep + function disputeGameFactory() external view returns (IDisputeGameFactory); + function initialize( + StartingAnchorRoot[] memory _startingAnchorRoots, + ISuperchainConfig _superchainConfig + ) + external; + function setAnchorState(IFaultDisputeGame _game) external; + function superchainConfig() external view returns (ISuperchainConfig); + function tryUpdateAnchorState() external; + function version() external view returns (string memory); + + function __constructor__(IDisputeGameFactory _disputeGameFactory) external; +} \ No newline at end of file diff --git a/op-verifier/contracts/lib/dispute/interfaces/IBigStepper.sol b/op-verifier/contracts/lib/dispute/interfaces/IBigStepper.sol new file mode 100644 index 00000000..cbdf9f82 --- /dev/null +++ b/op-verifier/contracts/lib/dispute/interfaces/IBigStepper.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import { IPreimageOracle } from "../lib/IPreimageOracle.sol"; + +/// @title IBigStepper +/// @notice Describes a state machine that can perform a single instruction step, provided a prestate and an optional +/// proof. +/// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +/// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣼⠶⢅⠒⢄⢔⣶⡦⣤⡤⠄⣀⠀⠀⠀⠀⠀⠀⠀ +/// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠨⡏⠀⠀⠈⠢⣙⢯⣄⠀⢨⠯⡺⡘⢄⠀⠀⠀⠀⠀ +/// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣶⡆⠀⠀⠀⠀⠈⠓⠬⡒⠡⣀⢙⡜⡀⠓⠄⠀⠀⠀ +/// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⡷⠿⣧⣀⡀⠀⠀⠀⠀⠀⠀⠉⠣⣞⠩⠥⠀⠼⢄⠀⠀ +/// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⡇⠀⠀⠀⠉⢹⣶⠒⠒⠂⠈⠉⠁⠘⡆⠀⣿⣿⠫⡄⠀ +/// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⢶⣤⣀⡀⠀⠀⢸⡿⠀⠀⠀⠀⠀⢀⠞⠀⠀⢡⢨⢀⡄⠀ +/// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⡒⣿⢿⡤⠝⡣⠉⠁⠚⠛⠀⠤⠤⣄⡰⠁⠀⠀⠀⠉⠙⢸⠀⠀ +/// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡤⢯⡌⡿⡇⠘⡷⠀⠁⠀⠀⢀⣰⠢⠲⠛⣈⣸⠦⠤⠶⠴⢬⣐⣊⡂⠀ +/// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣤⡪⡗⢫⠞⠀⠆⣀⠻⠤⠴⠐⠚⣉⢀⠦⠂⠋⠁⠀⠁⠀⠀⠀⠀⢋⠉⠇⠀ +/// ⠀⠀⠀⠀⣀⡤⠐⠒⠘⡹⠉⢸⠇⠸⠀⠀⠀⠀⣀⣤⠴⠚⠉⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠼⠀⣾⠀ +/// ⠀⠀⠀⡰⠀⠉⠉⠀⠁⠀⠀⠈⢇⠈⠒⠒⠘⠈⢀⢡⡂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⠀⢸⡄ +/// ⠀⠀⠸⣿⣆⠤⢀⡀⠀⠀⠀⠀⢘⡌⠀⠀⣀⣀⣀⡈⣤⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠀⢸⡇ +/// ⠀⠀⢸⣀⠀⠉⠒⠐⠛⠋⠭⠭⠍⠉⠛⠒⠒⠒⠀⠒⠚⠛⠛⠛⠩⠭⠭⠭⠭⠤⠤⠤⠤⠤⠭⠭⠉⠓⡆ +/// ⠀⠀⠘⠿⣷⣶⣤⣤⣀⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣤⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇ +/// ⠀⠀⠀⠀⠀⠉⠙⠛⠛⠻⠿⢿⣿⣿⣷⣶⣶⣶⣤⣤⣀⣁⣛⣃⣒⠿⠿⠿⠤⠠⠄⠤⠤⢤⣛⣓⣂⣻⡇ +/// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠉⠉⠙⠛⠻⠿⠿⠿⢿⣿⣿⣿⣷⣶⣶⣾⣿⣿⣿⣿⠿⠟⠁ +/// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠈⠉⠉⠉⠉⠁⠀⠀⠀⠀⠀ +interface IBigStepper { + /// @notice Performs the state transition from a given prestate and returns the hash of the post state witness. + /// @param _stateData The raw opaque prestate data. + /// @param _proof Opaque proof data, can be used to prove things about the prestate in relation to the state of the + /// interface's implementation. + /// @param _localContext The local key context for the preimage oracle. Optional, can be set as a constant if the + /// implementation only requires one set of local keys. + /// @return postState_ The hash of the post state witness after the state transition. + function step( + bytes calldata _stateData, + bytes calldata _proof, + bytes32 _localContext + ) + external + returns (bytes32 postState_); + + /// @notice Returns the preimage oracle used by the state machine. + function oracle() external view returns (IPreimageOracle oracle_); +} \ No newline at end of file diff --git a/op-verifier/contracts/lib/dispute/interfaces/IDelayedWETH.sol b/op-verifier/contracts/lib/dispute/interfaces/IDelayedWETH.sol new file mode 100644 index 00000000..f1aafffa --- /dev/null +++ b/op-verifier/contracts/lib/dispute/interfaces/IDelayedWETH.sol @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import { ISuperchainConfig } from "../lib/ISuperchainConfig.sol"; + +interface IDelayedWETH { + struct WithdrawalRequest { + uint256 amount; + uint256 timestamp; + } + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event Initialized(uint8 version); + event Unwrap(address indexed src, uint256 wad); + + fallback() external payable; + receive() external payable; + + function config() external view returns (ISuperchainConfig); + function delay() external view returns (uint256); + function hold(address _guy, uint256 _wad) external; + function initialize(address _owner, ISuperchainConfig _config) external; + function owner() external view returns (address); + function recover(uint256 _wad) external; + function transferOwnership(address newOwner) external; // nosemgrep + function renounceOwnership() external; + function unlock(address _guy, uint256 _wad) external; + function withdraw(address _guy, uint256 _wad) external; + function withdrawals(address, address) external view returns (uint256 amount, uint256 timestamp); + function version() external view returns (string memory); + + function withdraw(uint256 _wad) external; + + event Approval(address indexed src, address indexed guy, uint256 wad); + + event Transfer(address indexed src, address indexed dst, uint256 wad); + + event Deposit(address indexed dst, uint256 wad); + + event Withdrawal(address indexed src, uint256 wad); + + function name() external view returns (string memory); + + function symbol() external view returns (string memory); + + function decimals() external view returns (uint8); + + function balanceOf(address src) external view returns (uint256); + + function allowance(address owner, address spender) external view returns (uint256); + + function deposit() external payable; + + function totalSupply() external view returns (uint256); + + function approve(address guy, uint256 wad) external returns (bool); + + function transfer(address dst, uint256 wad) external returns (bool); + + function transferFrom(address src, address dst, uint256 wad) external returns (bool); + + function __constructor__(uint256 _delay) external; +} \ No newline at end of file diff --git a/op-verifier/contracts/lib/dispute/interfaces/IDisputeGame.sol b/op-verifier/contracts/lib/dispute/interfaces/IDisputeGame.sol new file mode 100644 index 00000000..e942c8d0 --- /dev/null +++ b/op-verifier/contracts/lib/dispute/interfaces/IDisputeGame.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import { IInitializable } from "./IInitializable.sol"; +import { Timestamp, GameStatus, GameType, Claim, Hash } from "../lib/Types.sol"; + +interface IDisputeGame is IInitializable { + event Resolved(GameStatus indexed status); + + function createdAt() external view returns (Timestamp); + function resolvedAt() external view returns (Timestamp); + function status() external view returns (GameStatus); + function gameType() external view returns (GameType gameType_); + function gameCreator() external pure returns (address creator_); + function rootClaim() external pure returns (Claim rootClaim_); + function l1Head() external pure returns (Hash l1Head_); + function extraData() external pure returns (bytes memory extraData_); + function resolve() external returns (GameStatus status_); + function gameData() external view returns (GameType gameType_, Claim rootClaim_, bytes memory extraData_); +} \ No newline at end of file diff --git a/op-verifier/contracts/lib/dispute/interfaces/IDisputeGameFactory.sol b/op-verifier/contracts/lib/dispute/interfaces/IDisputeGameFactory.sol new file mode 100644 index 00000000..cdffe9f3 --- /dev/null +++ b/op-verifier/contracts/lib/dispute/interfaces/IDisputeGameFactory.sol @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import { IDisputeGame } from "./IDisputeGame.sol"; +import { GameId, Timestamp, Claim, Hash, GameType } from "../lib/Types.sol"; + +interface IDisputeGameFactory { + struct GameSearchResult { + uint256 index; + GameId metadata; + Timestamp timestamp; + Claim rootClaim; + bytes extraData; + } + + error GameAlreadyExists(Hash uuid); + error IncorrectBondAmount(); + error NoImplementation(GameType gameType); + + event DisputeGameCreated(address indexed disputeProxy, GameType indexed gameType, Claim indexed rootClaim); + event ImplementationSet(address indexed impl, GameType indexed gameType); + event InitBondUpdated(GameType indexed gameType, uint256 indexed newBond); + event Initialized(uint8 version); + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + function create( + GameType _gameType, + Claim _rootClaim, + bytes memory _extraData + ) + external + payable + returns (IDisputeGame proxy_); + function findLatestGames( + GameType _gameType, + uint256 _start, + uint256 _n + ) + external + view + returns (GameSearchResult[] memory games_); + function gameAtIndex(uint256 _index) + external + view + returns (GameType gameType_, Timestamp timestamp_, IDisputeGame proxy_); + function gameCount() external view returns (uint256 gameCount_); + function gameImpls(GameType) external view returns (IDisputeGame); + function games( + GameType _gameType, + Claim _rootClaim, + bytes memory _extraData + ) + external + view + returns (IDisputeGame proxy_, Timestamp timestamp_); + function getGameUUID( + GameType _gameType, + Claim _rootClaim, + bytes memory _extraData + ) + external + pure + returns (Hash uuid_); + function initBonds(GameType) external view returns (uint256); + function initialize(address _owner) external; + function owner() external view returns (address); + function renounceOwnership() external; + function setImplementation(GameType _gameType, IDisputeGame _impl) external; + function setInitBond(GameType _gameType, uint256 _initBond) external; + function transferOwnership(address newOwner) external; // nosemgrep + function version() external view returns (string memory); + + function __constructor__() external; +} \ No newline at end of file diff --git a/op-verifier/contracts/lib/dispute/interfaces/IFaultDisputeGame.sol b/op-verifier/contracts/lib/dispute/interfaces/IFaultDisputeGame.sol new file mode 100644 index 00000000..86cbf263 --- /dev/null +++ b/op-verifier/contracts/lib/dispute/interfaces/IFaultDisputeGame.sol @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import { IDisputeGame } from "./IDisputeGame.sol"; +import { IDelayedWETH } from "./IDelayedWETH.sol"; +import { IAnchorStateRegistry } from "./IAnchorStateRegistry.sol"; +import { IBigStepper } from "./IBigStepper.sol"; +import { Types } from "@eth-optimism/contracts-bedrock/src/libraries/Types.sol"; +import { GameType, Claim, Position, Clock, Hash, Duration } from "../lib/Types.sol"; + +interface IFaultDisputeGame is IDisputeGame { + struct ClaimData { + uint32 parentIndex; + address counteredBy; + address claimant; + uint128 bond; + Claim claim; + Position position; + Clock clock; + } + + struct ResolutionCheckpoint { + bool initialCheckpointComplete; + uint32 subgameIndex; + Position leftmostPosition; + address counteredBy; + } + + error AlreadyInitialized(); + error AnchorRootNotFound(); + error BlockNumberMatches(); + error BondTransferFailed(); + error CannotDefendRootClaim(); + error ClaimAboveSplit(); + error ClaimAlreadyExists(); + error ClaimAlreadyResolved(); + error ClockNotExpired(); + error ClockTimeExceeded(); + error ContentLengthMismatch(); + error DuplicateStep(); + error EmptyItem(); + error GameDepthExceeded(); + error GameNotInProgress(); + error IncorrectBondAmount(); + error InvalidChallengePeriod(); + error InvalidClockExtension(); + error InvalidDataRemainder(); + error InvalidDisputedClaimIndex(); + error InvalidHeader(); + error InvalidHeaderRLP(); + error InvalidLocalIdent(); + error InvalidOutputRootProof(); + error InvalidParent(); + error InvalidPrestate(); + error InvalidSplitDepth(); + error L2BlockNumberChallenged(); + error MaxDepthTooLarge(); + error NoCreditToClaim(); + error OutOfOrderResolution(); + error UnexpectedList(); + error UnexpectedRootClaim(Claim rootClaim); + error UnexpectedString(); + error ValidStep(); + + event Move(uint256 indexed parentIndex, Claim indexed claim, address indexed claimant); + + function absolutePrestate() external view returns (Claim absolutePrestate_); + function addLocalData(uint256 _ident, uint256 _execLeafIdx, uint256 _partOffset) external; + function anchorStateRegistry() external view returns (IAnchorStateRegistry registry_); + function attack(Claim _disputed, uint256 _parentIndex, Claim _claim) external payable; + function challengeRootL2Block(Types.OutputRootProof memory _outputRootProof, bytes memory _headerRLP) external; + function claimCredit(address _recipient) external; + function claimData(uint256) + external + view // nosemgrep + returns ( + uint32 parentIndex, + address counteredBy, + address claimant, + uint128 bond, + Claim claim, + Position position, + Clock clock + ); + function claimDataLen() external view returns (uint256 len_); + function claims(Hash) external view returns (bool); + function clockExtension() external view returns (Duration clockExtension_); + function credit(address) external view returns (uint256); + function defend(Claim _disputed, uint256 _parentIndex, Claim _claim) external payable; + function getChallengerDuration(uint256 _claimIndex) external view returns (Duration duration_); + function getNumToResolve(uint256 _claimIndex) external view returns (uint256 numRemainingChildren_); + function getRequiredBond(Position _position) external view returns (uint256 requiredBond_); + function l2BlockNumber() external pure returns (uint256 l2BlockNumber_); + function l2BlockNumberChallenged() external view returns (bool); + function l2BlockNumberChallenger() external view returns (address); + function l2ChainId() external view returns (uint256 l2ChainId_); + function maxClockDuration() external view returns (Duration maxClockDuration_); + function maxGameDepth() external view returns (uint256 maxGameDepth_); + function move(Claim _disputed, uint256 _challengeIndex, Claim _claim, bool _isAttack) external payable; + function resolutionCheckpoints(uint256) + external + view + returns (bool initialCheckpointComplete, uint32 subgameIndex, Position leftmostPosition, address counteredBy); // nosemgrep + function resolveClaim(uint256 _claimIndex, uint256 _numToResolve) external; + function resolvedSubgames(uint256) external view returns (bool); + function splitDepth() external view returns (uint256 splitDepth_); + function startingBlockNumber() external view returns (uint256 startingBlockNumber_); + function startingOutputRoot() external view returns (Hash root, uint256 l2BlockNumber); // nosemgrep + function startingRootHash() external view returns (Hash startingRootHash_); + function step(uint256 _claimIndex, bool _isAttack, bytes memory _stateData, bytes memory _proof) external; + function subgames(uint256, uint256) external view returns (uint256); + function version() external view returns (string memory); + function vm() external view returns (IBigStepper vm_); + function weth() external view returns (IDelayedWETH weth_); + + function __constructor__( + GameType _gameType, + Claim _absolutePrestate, + uint256 _maxGameDepth, + uint256 _splitDepth, + Duration _clockExtension, + Duration _maxClockDuration, + IBigStepper _vm, + IDelayedWETH _weth, + IAnchorStateRegistry _anchorStateRegistry, + uint256 _l2ChainId + ) + external; +} \ No newline at end of file diff --git a/op-verifier/contracts/lib/dispute/interfaces/IInitializable.sol b/op-verifier/contracts/lib/dispute/interfaces/IInitializable.sol new file mode 100644 index 00000000..ae4fa4a6 --- /dev/null +++ b/op-verifier/contracts/lib/dispute/interfaces/IInitializable.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface IInitializable { + function initialize() external payable; +} \ No newline at end of file diff --git a/op-verifier/contracts/lib/dispute/lib/CannonTypes.sol b/op-verifier/contracts/lib/dispute/lib/CannonTypes.sol new file mode 100644 index 00000000..0432677b --- /dev/null +++ b/op-verifier/contracts/lib/dispute/lib/CannonTypes.sol @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.15; + +using LPPMetadataLib for LPPMetaData global; + +/// @notice Packed LPP metadata. +/// ┌─────────────┬────────────────────────────────────────────┐ +/// │ Bit Offsets │ Description │ +/// ├─────────────┼────────────────────────────────────────────┤ +/// │ [0, 64) │ Timestamp (Finalized - All data available) │ +/// │ [64, 96) │ Part Offset │ +/// │ [96, 128) │ Claimed Size │ +/// │ [128, 160) │ Blocks Processed (Inclusive of Padding) │ +/// │ [160, 192) │ Bytes Processed (Non-inclusive of Padding) │ +/// │ [192, 256) │ Countered │ +/// └─────────────┴────────────────────────────────────────────┘ +type LPPMetaData is bytes32; + +/// @notice LPP metadata UDT extension functions. +library LPPMetadataLib { + uint256 private constant U64_MASK = 0xFFFFFFFFFFFFFFFF; + uint256 private constant U32_MASK = 0xFFFFFFFF; + + function setTimestamp(LPPMetaData _self, uint64 _timestamp) internal pure returns (LPPMetaData self_) { + assembly { + self_ := or(shl(192, _timestamp), and(_self, not(shl(192, U64_MASK)))) + } + } + + function setPartOffset(LPPMetaData _self, uint32 _partOffset) internal pure returns (LPPMetaData self_) { + assembly { + self_ := or(shl(160, _partOffset), and(_self, not(shl(160, U32_MASK)))) + } + } + + function setClaimedSize(LPPMetaData _self, uint32 _claimedSize) internal pure returns (LPPMetaData self_) { + assembly { + self_ := or(shl(128, _claimedSize), and(_self, not(shl(128, U32_MASK)))) + } + } + + function setBlocksProcessed(LPPMetaData _self, uint32 _blocksProcessed) internal pure returns (LPPMetaData self_) { + assembly { + self_ := or(shl(96, _blocksProcessed), and(_self, not(shl(96, U32_MASK)))) + } + } + + function setBytesProcessed(LPPMetaData _self, uint32 _bytesProcessed) internal pure returns (LPPMetaData self_) { + assembly { + self_ := or(shl(64, _bytesProcessed), and(_self, not(shl(64, U32_MASK)))) + } + } + + function setCountered(LPPMetaData _self, bool _countered) internal pure returns (LPPMetaData self_) { + assembly { + self_ := or(_countered, and(_self, not(U64_MASK))) + } + } + + function timestamp(LPPMetaData _self) internal pure returns (uint64 timestamp_) { + assembly { + timestamp_ := shr(192, _self) + } + } + + function partOffset(LPPMetaData _self) internal pure returns (uint64 partOffset_) { + assembly { + partOffset_ := and(shr(160, _self), U32_MASK) + } + } + + function claimedSize(LPPMetaData _self) internal pure returns (uint32 claimedSize_) { + assembly { + claimedSize_ := and(shr(128, _self), U32_MASK) + } + } + + function blocksProcessed(LPPMetaData _self) internal pure returns (uint32 blocksProcessed_) { + assembly { + blocksProcessed_ := and(shr(96, _self), U32_MASK) + } + } + + function bytesProcessed(LPPMetaData _self) internal pure returns (uint32 bytesProcessed_) { + assembly { + bytesProcessed_ := and(shr(64, _self), U32_MASK) + } + } + + function countered(LPPMetaData _self) internal pure returns (bool countered_) { + assembly { + countered_ := and(_self, U64_MASK) + } + } +} \ No newline at end of file diff --git a/op-verifier/contracts/lib/dispute/lib/IPreimageOracle.sol b/op-verifier/contracts/lib/dispute/lib/IPreimageOracle.sol new file mode 100644 index 00000000..764290fa --- /dev/null +++ b/op-verifier/contracts/lib/dispute/lib/IPreimageOracle.sol @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import { LibKeccak } from "./LibKeccak.sol"; +import { LPPMetaData } from "./CannonTypes.sol"; + +interface IPreimageOracle { + struct Leaf { + bytes input; + uint256 index; + bytes32 stateCommitment; + } + + error ActiveProposal(); + error AlreadyFinalized(); + error AlreadyInitialized(); + error BadProposal(); + error BondTransferFailed(); + error InsufficientBond(); + error InvalidInputSize(); + error InvalidPreimage(); + error InvalidProof(); + error NotEOA(); + error NotInitialized(); + error PartOffsetOOB(); + error PostStateMatches(); + error StatesNotContiguous(); + error TreeSizeOverflow(); + error WrongStartingBlock(); + + function KECCAK_TREE_DEPTH() external view returns (uint256); + function MAX_LEAF_COUNT() external view returns (uint256); + function MIN_BOND_SIZE() external view returns (uint256); + function PRECOMPILE_CALL_RESERVED_GAS() external view returns (uint256); + function addLeavesLPP( + uint256 _uuid, + uint256 _inputStartBlock, + bytes memory _input, + bytes32[] memory _stateCommitments, + bool _finalize + ) + external; + function challengeFirstLPP( + address _claimant, + uint256 _uuid, + Leaf memory _postState, + bytes32[] memory _postStateProof + ) + external; + function challengeLPP( + address _claimant, + uint256 _uuid, + LibKeccak.StateMatrix memory _stateMatrix, + Leaf memory _preState, + bytes32[] memory _preStateProof, + Leaf memory _postState, + bytes32[] memory _postStateProof + ) + external; + function challengePeriod() external view returns (uint256 challengePeriod_); + function getTreeRootLPP(address _owner, uint256 _uuid) external view returns (bytes32 treeRoot_); + function initLPP(uint256 _uuid, uint32 _partOffset, uint32 _claimedSize) external payable; + function loadBlobPreimagePart( + uint256 _z, + uint256 _y, + bytes memory _commitment, + bytes memory _proof, + uint256 _partOffset + ) + external; + function loadKeccak256PreimagePart(uint256 _partOffset, bytes memory _preimage) external; + function loadLocalData( + uint256 _ident, + bytes32 _localContext, + bytes32 _word, + uint256 _size, + uint256 _partOffset + ) + external + returns (bytes32 key_); + function loadPrecompilePreimagePart( + uint256 _partOffset, + address _precompile, + uint64 _requiredGas, + bytes memory _input + ) + external; + function loadSha256PreimagePart(uint256 _partOffset, bytes memory _preimage) external; + function minProposalSize() external view returns (uint256 minProposalSize_); + function preimageLengths(bytes32) external view returns (uint256); + function preimagePartOk(bytes32, uint256) external view returns (bool); + function preimageParts(bytes32, uint256) external view returns (bytes32); + function proposalBlocks(address, uint256, uint256) external view returns (uint64); + function proposalBlocksLen(address _claimant, uint256 _uuid) external view returns (uint256 len_); + function proposalBonds(address, uint256) external view returns (uint256); + function proposalBranches(address, uint256, uint256) external view returns (bytes32); + function proposalCount() external view returns (uint256 count_); + function proposalMetadata(address, uint256) external view returns (LPPMetaData); + function proposalParts(address, uint256) external view returns (bytes32); + function proposals(uint256) external view returns (address claimant, uint256 uuid); // nosemgrep: + // sol-style-return-arg-fmt + function readPreimage(bytes32 _key, uint256 _offset) external view returns (bytes32 dat_, uint256 datLen_); + function squeezeLPP( + address _claimant, + uint256 _uuid, + LibKeccak.StateMatrix memory _stateMatrix, + Leaf memory _preState, + bytes32[] memory _preStateProof, + Leaf memory _postState, + bytes32[] memory _postStateProof + ) + external; + function version() external view returns (string memory); + function zeroHashes(uint256) external view returns (bytes32); + + function __constructor__(uint256 _minProposalSize, uint256 _challengePeriod) external; +} \ No newline at end of file diff --git a/op-verifier/contracts/lib/dispute/lib/ISuperchainConfig.sol b/op-verifier/contracts/lib/dispute/lib/ISuperchainConfig.sol new file mode 100644 index 00000000..2a72bd99 --- /dev/null +++ b/op-verifier/contracts/lib/dispute/lib/ISuperchainConfig.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface ISuperchainConfig { + enum UpdateType { + GUARDIAN + } + + event ConfigUpdate(UpdateType indexed updateType, bytes data); + event Initialized(uint8 version); + event Paused(string identifier); + event Unpaused(); + + function GUARDIAN_SLOT() external view returns (bytes32); + function PAUSED_SLOT() external view returns (bytes32); + function guardian() external view returns (address guardian_); + function initialize(address _guardian, bool _paused) external; + function pause(string memory _identifier) external; + function paused() external view returns (bool paused_); + function unpause() external; + function version() external view returns (string memory); + + function __constructor__() external; +} \ No newline at end of file diff --git a/op-verifier/contracts/lib/dispute/lib/LibKeccak.sol b/op-verifier/contracts/lib/dispute/lib/LibKeccak.sol new file mode 100644 index 00000000..6a04dc29 --- /dev/null +++ b/op-verifier/contracts/lib/dispute/lib/LibKeccak.sol @@ -0,0 +1,387 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +/// @title LibKeccak +/// @notice An EVM implementation of the Keccak-f[1600] permutation. +/// @author clabby +/// @custom:attribution geohot +library LibKeccak { + /// @notice The block size of the Keccak-f[1600] permutation, 1088 bits (136 bytes). + uint256 internal constant BLOCK_SIZE_BYTES = 136; + + /// @notice The round constants for the keccak256 hash function. Packed in memory for efficient reading during the + /// permutation. + bytes internal constant ROUND_CONSTANTS = abi.encode( + 0x00000000000000010000000000008082800000000000808a8000000080008000, // r1,r2,r3,r4 + 0x000000000000808b000000008000000180000000800080818000000000008009, // r5,r6,r7,r8 + 0x000000000000008a00000000000000880000000080008009000000008000000a, // r9,r10,r11,r12 + 0x000000008000808b800000000000008b80000000000080898000000000008003, // r13,r14,r15,r16 + 0x80000000000080028000000000000080000000000000800a800000008000000a, // r17,r18,r19,r20 + 0x8000000080008081800000000000808000000000800000018000000080008008 // r21,r22,r23,r24 + ); + + /// @notice A mask for 64-bit values. + uint64 private constant U64_MASK = 0xFFFFFFFFFFFFFFFF; + + /// @notice The 5x5 state matrix for the keccak-f[1600] permutation. + struct StateMatrix { + uint64[25] state; + } + + /// @notice Performs the Keccak-f[1600] permutation on the given 5x5 state matrix. + function permutation(StateMatrix memory _stateMatrix) internal pure { + // Pull the round constants into memory to avoid reallocation in the unrolled permutation loop. + bytes memory roundConstants = ROUND_CONSTANTS; + + assembly { + // Add 32 to the state matrix pointer to skip the data location field. + let stateMatrixPtr := add(_stateMatrix, 0x20) + let rcPtr := add(roundConstants, 0x20) + + // set a state element in the passed `StateMatrix` struct memory ptr. + function setStateElem(ptr, idx, data) { + mstore(add(ptr, shl(0x05, idx)), and(data, U64_MASK)) + } + + // fetch a state element from the passed `StateMatrix` struct memory ptr. + function stateElem(ptr, idx) -> elem { + elem := mload(add(ptr, shl(0x05, idx))) + } + + // 64 bit logical shift + function shl64(a, b) -> val { + val := and(shl(a, b), U64_MASK) + } + + // Performs an indivudual rho + pi computation, to be used in the full `thetaRhoPi` chain. + function rhoPi(ptr, destIdx, srcIdx, fact, dt) { + let xs1 := xor(stateElem(ptr, srcIdx), dt) + let res := xor(shl(fact, xs1), shr(sub(64, fact), xs1)) + setStateElem(ptr, destIdx, res) + } + + // xor a column in the state matrix + function xorColumn(ptr, col) -> val { + val := + xor( + xor(xor(stateElem(ptr, col), stateElem(ptr, add(col, 5))), stateElem(ptr, add(col, 10))), + xor(stateElem(ptr, add(col, 15)), stateElem(ptr, add(col, 20))) + ) + } + + // Performs the `theta`, `rho`, and `pi` steps of the Keccak-f[1600] permutation on + // the passed `StateMatrix` struct memory ptr. + function thetaRhoPi(ptr) { + // Theta + let C0 := xorColumn(ptr, 0) + let C1 := xorColumn(ptr, 1) + let C2 := xorColumn(ptr, 2) + let C3 := xorColumn(ptr, 3) + let C4 := xorColumn(ptr, 4) + let D0 := xor(xor(shl64(1, C1), shr(63, C1)), C4) + let D1 := xor(xor(shl64(1, C2), shr(63, C2)), C0) + let D2 := xor(xor(shl64(1, C3), shr(63, C3)), C1) + let D3 := xor(xor(shl64(1, C4), shr(63, C4)), C2) + let D4 := xor(xor(shl64(1, C0), shr(63, C0)), C3) + + let xs1 := xor(stateElem(ptr, 1), D1) + let A1 := xor(shl(1, xs1), shr(63, xs1)) + + let _ptr := ptr + setStateElem(_ptr, 0, xor(stateElem(_ptr, 0), D0)) + rhoPi(_ptr, 1, 6, 44, D1) + rhoPi(_ptr, 6, 9, 20, D4) + rhoPi(_ptr, 9, 22, 61, D2) + rhoPi(_ptr, 22, 14, 39, D4) + rhoPi(_ptr, 14, 20, 18, D0) + rhoPi(_ptr, 20, 2, 62, D2) + rhoPi(_ptr, 2, 12, 43, D2) + rhoPi(_ptr, 12, 13, 25, D3) + rhoPi(_ptr, 13, 19, 8, D4) + rhoPi(_ptr, 19, 23, 56, D3) + rhoPi(_ptr, 23, 15, 41, D0) + rhoPi(_ptr, 15, 4, 27, D4) + rhoPi(_ptr, 4, 24, 14, D4) + rhoPi(_ptr, 24, 21, 2, D1) + rhoPi(_ptr, 21, 8, 55, D3) + rhoPi(_ptr, 8, 16, 45, D1) + rhoPi(_ptr, 16, 5, 36, D0) + rhoPi(_ptr, 5, 3, 28, D3) + rhoPi(_ptr, 3, 18, 21, D3) + rhoPi(_ptr, 18, 17, 15, D2) + rhoPi(_ptr, 17, 11, 10, D1) + rhoPi(_ptr, 11, 7, 6, D2) + rhoPi(_ptr, 7, 10, 3, D0) + setStateElem(_ptr, 10, A1) + } + + // Inner `chi` function, unrolled in `chi` for performance. + function innerChi(ptr, start) { + let A0 := stateElem(ptr, start) + let A1 := stateElem(ptr, add(start, 1)) + let A2 := stateElem(ptr, add(start, 2)) + let A3 := stateElem(ptr, add(start, 3)) + let A4 := stateElem(ptr, add(start, 4)) + + setStateElem(ptr, start, xor(A0, and(not(A1), A2))) + setStateElem(ptr, add(start, 1), xor(A1, and(not(A2), A3))) + setStateElem(ptr, add(start, 2), xor(A2, and(not(A3), A4))) + setStateElem(ptr, add(start, 3), xor(A3, and(not(A4), A0))) + setStateElem(ptr, add(start, 4), xor(A4, and(not(A0), A1))) + } + + // Performs the `chi` step of the Keccak-f[1600] permutation on the passed `StateMatrix` struct memory ptr + function chi(ptr) { + innerChi(ptr, 0) + innerChi(ptr, 5) + innerChi(ptr, 10) + innerChi(ptr, 15) + innerChi(ptr, 20) + } + + // Perform the full Keccak-f[1600] permutation on a `StateMatrix` struct memory ptr for a given round. + function permute(ptr, roundsPtr, round) { + // Theta, Rho, Pi, Chi + thetaRhoPi(ptr) + chi(ptr) + // Iota + let roundConst := shr(192, mload(add(roundsPtr, shl(0x03, round)))) + setStateElem(ptr, 0, xor(stateElem(ptr, 0), roundConst)) + } + + // Unroll the permutation loop. + permute(stateMatrixPtr, rcPtr, 0) + permute(stateMatrixPtr, rcPtr, 1) + permute(stateMatrixPtr, rcPtr, 2) + permute(stateMatrixPtr, rcPtr, 3) + permute(stateMatrixPtr, rcPtr, 4) + permute(stateMatrixPtr, rcPtr, 5) + permute(stateMatrixPtr, rcPtr, 6) + permute(stateMatrixPtr, rcPtr, 7) + permute(stateMatrixPtr, rcPtr, 8) + permute(stateMatrixPtr, rcPtr, 9) + permute(stateMatrixPtr, rcPtr, 10) + permute(stateMatrixPtr, rcPtr, 11) + permute(stateMatrixPtr, rcPtr, 12) + permute(stateMatrixPtr, rcPtr, 13) + permute(stateMatrixPtr, rcPtr, 14) + permute(stateMatrixPtr, rcPtr, 15) + permute(stateMatrixPtr, rcPtr, 16) + permute(stateMatrixPtr, rcPtr, 17) + permute(stateMatrixPtr, rcPtr, 18) + permute(stateMatrixPtr, rcPtr, 19) + permute(stateMatrixPtr, rcPtr, 20) + permute(stateMatrixPtr, rcPtr, 21) + permute(stateMatrixPtr, rcPtr, 22) + permute(stateMatrixPtr, rcPtr, 23) + } + } + + /// @notice Absorb a fixed-sized block into the sponge. + function absorb(StateMatrix memory _stateMatrix, bytes memory _input) internal pure { + assembly { + // The input must be 1088 bits long. + if iszero(eq(mload(_input), BLOCK_SIZE_BYTES)) { revert(0, 0) } + + let dataPtr := add(_input, 0x20) + let statePtr := add(_stateMatrix, 0x20) + + // set a state element in the passed `StateMatrix` struct memory ptr. + function setStateElem(ptr, idx, data) { + mstore(add(ptr, shl(0x05, idx)), and(data, U64_MASK)) + } + + // fetch a state element from the passed `StateMatrix` struct memory ptr. + function stateElem(ptr, idx) -> elem { + elem := mload(add(ptr, shl(0x05, idx))) + } + + // Inner sha3 absorb XOR function + function absorbInner(stateMatrixPtr, inputPtr, idx) { + let boWord := mload(add(inputPtr, shl(3, idx))) + + let res := + or( + or( + or(shl(56, byte(7, boWord)), shl(48, byte(6, boWord))), + or(shl(40, byte(5, boWord)), shl(32, byte(4, boWord))) + ), + or( + or(shl(24, byte(3, boWord)), shl(16, byte(2, boWord))), + or(shl(8, byte(1, boWord)), byte(0, boWord)) + ) + ) + setStateElem(stateMatrixPtr, idx, xor(stateElem(stateMatrixPtr, idx), res)) + } + + // Unroll the input XOR loop. + absorbInner(statePtr, dataPtr, 0) + absorbInner(statePtr, dataPtr, 1) + absorbInner(statePtr, dataPtr, 2) + absorbInner(statePtr, dataPtr, 3) + absorbInner(statePtr, dataPtr, 4) + absorbInner(statePtr, dataPtr, 5) + absorbInner(statePtr, dataPtr, 6) + absorbInner(statePtr, dataPtr, 7) + absorbInner(statePtr, dataPtr, 8) + absorbInner(statePtr, dataPtr, 9) + absorbInner(statePtr, dataPtr, 10) + absorbInner(statePtr, dataPtr, 11) + absorbInner(statePtr, dataPtr, 12) + absorbInner(statePtr, dataPtr, 13) + absorbInner(statePtr, dataPtr, 14) + absorbInner(statePtr, dataPtr, 15) + absorbInner(statePtr, dataPtr, 16) + } + } + + /// @notice Squeezes the final keccak256 digest from the passed `StateMatrix`. + function squeeze(StateMatrix memory _stateMatrix) internal pure returns (bytes32 hash_) { + assembly { + // 64 bit logical shift + function shl64(a, b) -> val { + val := and(shl(a, b), U64_MASK) + } + + // convert a big endian 64-bit value to a little endian 64-bit value. + function toLE(beVal) -> leVal { + beVal := or(and(shl64(8, beVal), 0xFF00FF00FF00FF00), and(shr(8, beVal), 0x00FF00FF00FF00FF)) + beVal := or(and(shl64(16, beVal), 0xFFFF0000FFFF0000), and(shr(16, beVal), 0x0000FFFF0000FFFF)) + leVal := or(shl64(32, beVal), shr(32, beVal)) + } + + // fetch a state element from the passed `StateMatrix` struct memory ptr. + function stateElem(ptr, idx) -> elem { + elem := mload(add(ptr, shl(0x05, idx))) + } + + let stateMatrixPtr := add(_stateMatrix, 0x20) + hash_ := + or( + or(shl(192, toLE(stateElem(stateMatrixPtr, 0))), shl(128, toLE(stateElem(stateMatrixPtr, 1)))), + or(shl(64, toLE(stateElem(stateMatrixPtr, 2))), toLE(stateElem(stateMatrixPtr, 3))) + ) + } + } + + /// @notice Pads input data to an even multiple of the Keccak-f[1600] permutation block size, 1088 bits (136 bytes). + function pad(bytes calldata _data) internal pure returns (bytes memory padded_) { + assembly { + padded_ := mload(0x40) + + // Grab the original length of `_data` + let len := _data.length + + let dataPtr := add(padded_, 0x20) + let endPtr := add(dataPtr, len) + + // Copy the data into memory. + calldatacopy(dataPtr, _data.offset, len) + + let modBlockSize := mod(len, BLOCK_SIZE_BYTES) + switch modBlockSize + case false { + // Clean the full padding block. It is possible that this memory is dirty, since solidity sometimes does + // not update the free memory pointer when allocating memory, for example with external calls. To do + // this, we read out-of-bounds from the calldata, which will always return 0 bytes. + calldatacopy(endPtr, calldatasize(), BLOCK_SIZE_BYTES) + + // If the input is a perfect multiple of the block size, then we add a full extra block of padding. + mstore8(endPtr, 0x01) + mstore8(sub(add(endPtr, BLOCK_SIZE_BYTES), 0x01), 0x80) + + // Update the length of the data to include the padding. + mstore(padded_, add(len, BLOCK_SIZE_BYTES)) + } + default { + // If the input is not a perfect multiple of the block size, then we add a partial block of padding. + // This should entail a set bit after the input, followed by as many zero bits as necessary to fill + // the block, followed by a single 1 bit in the lowest-order bit of the final block. + + let remaining := sub(BLOCK_SIZE_BYTES, modBlockSize) + let newLen := add(len, remaining) + let paddedEndPtr := add(dataPtr, newLen) + + // Clean the remainder to ensure that the intermediate data between the padding bits is 0. It is + // possible that this memory is dirty, since solidity sometimes does not update the free memory pointer + // when allocating memory, for example with external calls. To do this, we read out-of-bounds from the + // calldata, which will always return 0 bytes. + let partialRemainder := sub(paddedEndPtr, endPtr) + calldatacopy(endPtr, calldatasize(), partialRemainder) + + // Store the padding bits. + mstore8(sub(paddedEndPtr, 0x01), 0x80) + mstore8(endPtr, or(byte(0x00, mload(endPtr)), 0x01)) + + // Update the length of the data to include the padding. The length should be a multiple of the + // block size after this. + mstore(padded_, newLen) + } + + // Update the free memory pointer. + mstore(0x40, add(padded_, and(add(mload(padded_), 0x3F), not(0x1F)))) + } + } + + /// @notice Pads input data to an even multiple of the Keccak-f[1600] permutation block size, 1088 bits (136 bytes). + function padMemory(bytes memory _data) internal pure returns (bytes memory padded_) { + assembly { + padded_ := mload(0x40) + + // Grab the original length of `_data` + let len := mload(_data) + + let dataPtr := add(padded_, 0x20) + let endPtr := add(dataPtr, len) + + // Copy the data. + let originalDataPtr := add(_data, 0x20) + for { let i := 0x00 } lt(i, len) { i := add(i, 0x20) } { + mstore(add(dataPtr, i), mload(add(originalDataPtr, i))) + } + + let modBlockSize := mod(len, BLOCK_SIZE_BYTES) + switch modBlockSize + case false { + // Clean the full padding block. It is possible that this memory is dirty, since solidity sometimes does + // not update the free memory pointer when allocating memory, for example with external calls. To do + // this, we read out-of-bounds from the calldata, which will always return 0 bytes. + calldatacopy(endPtr, calldatasize(), BLOCK_SIZE_BYTES) + + // If the input is a perfect multiple of the block size, then we add a full extra block of padding. + mstore8(sub(add(endPtr, BLOCK_SIZE_BYTES), 0x01), 0x80) + mstore8(endPtr, 0x01) + + // Update the length of the data to include the padding. + mstore(padded_, add(len, BLOCK_SIZE_BYTES)) + } + default { + // If the input is not a perfect multiple of the block size, then we add a partial block of padding. + // This should entail a set bit after the input, followed by as many zero bits as necessary to fill + // the block, followed by a single 1 bit in the lowest-order bit of the final block. + + let remaining := sub(BLOCK_SIZE_BYTES, modBlockSize) + let newLen := add(len, remaining) + let paddedEndPtr := add(dataPtr, newLen) + + // Clean the remainder to ensure that the intermediate data between the padding bits is 0. It is + // possible that this memory is dirty, since solidity sometimes does not update the free memory pointer + // when allocating memory, for example with external calls. To do this, we read out-of-bounds from the + // calldata, which will always return 0 bytes. + let partialRemainder := sub(paddedEndPtr, endPtr) + calldatacopy(endPtr, calldatasize(), partialRemainder) + + // Store the padding bits. + mstore8(sub(paddedEndPtr, 0x01), 0x80) + mstore8(endPtr, or(byte(0x00, mload(endPtr)), 0x01)) + + // Update the length of the data to include the padding. The length should be a multiple of the + // block size after this. + mstore(padded_, newLen) + } + + // Update the free memory pointer. + mstore(0x40, add(padded_, and(add(mload(padded_), 0x3F), not(0x1F)))) + } + } +} \ No newline at end of file diff --git a/op-verifier/contracts/lib/dispute/lib/LibPosition.sol b/op-verifier/contracts/lib/dispute/lib/LibPosition.sol new file mode 100644 index 00000000..8cc08844 --- /dev/null +++ b/op-verifier/contracts/lib/dispute/lib/LibPosition.sol @@ -0,0 +1,204 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.15; + +using LibPosition for Position global; + +/// @notice A `Position` represents a position of a claim within the game tree. +/// @dev This is represented as a "generalized index" where the high-order bit +/// is the level in the tree and the remaining bits is a unique bit pattern, allowing +/// a unique identifier for each node in the tree. Mathematically, it is calculated +/// as 2^{depth} + indexAtDepth. +type Position is uint128; + +/// @title LibPosition +/// @notice This library contains helper functions for working with the `Position` type. +library LibPosition { + /// @notice the `MAX_POSITION_BITLEN` is the number of bits that the `Position` type, and the implementation of + /// its behavior within this library, can safely support. + uint8 internal constant MAX_POSITION_BITLEN = 126; + + /// @notice Computes a generalized index (2^{depth} + indexAtDepth). + /// @param _depth The depth of the position. + /// @param _indexAtDepth The index at the depth of the position. + /// @return position_ The computed generalized index. + function wrap(uint8 _depth, uint128 _indexAtDepth) internal pure returns (Position position_) { + assembly { + // gindex = 2^{_depth} + _indexAtDepth + position_ := add(shl(_depth, 1), _indexAtDepth) + } + } + + /// @notice Pulls the `depth` out of a `Position` type. + /// @param _position The generalized index to get the `depth` of. + /// @return depth_ The `depth` of the `position` gindex. + /// @custom:attribution Solady + function depth(Position _position) internal pure returns (uint8 depth_) { + // Return the most significant bit offset, which signifies the depth of the gindex. + assembly { + depth_ := or(depth_, shl(6, lt(0xffffffffffffffff, shr(depth_, _position)))) + depth_ := or(depth_, shl(5, lt(0xffffffff, shr(depth_, _position)))) + + // For the remaining 32 bits, use a De Bruijn lookup. + _position := shr(depth_, _position) + _position := or(_position, shr(1, _position)) + _position := or(_position, shr(2, _position)) + _position := or(_position, shr(4, _position)) + _position := or(_position, shr(8, _position)) + _position := or(_position, shr(16, _position)) + + depth_ := + or( + depth_, + byte( + shr(251, mul(_position, shl(224, 0x07c4acdd))), + 0x0009010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f + ) + ) + } + } + + /// @notice Pulls the `indexAtDepth` out of a `Position` type. + /// The `indexAtDepth` is the left/right index of a position at a specific depth within + /// the binary tree, starting from index 0. For example, at gindex 2, the `depth` = 1 + /// and the `indexAtDepth` = 0. + /// @param _position The generalized index to get the `indexAtDepth` of. + /// @return indexAtDepth_ The `indexAtDepth` of the `position` gindex. + function indexAtDepth(Position _position) internal pure returns (uint128 indexAtDepth_) { + // Return bits p_{msb-1}...p_{0}. This effectively pulls the 2^{depth} out of the gindex, + // leaving only the `indexAtDepth`. + uint256 msb = depth(_position); + assembly { + indexAtDepth_ := sub(_position, shl(msb, 1)) + } + } + + /// @notice Get the left child of `_position`. + /// @param _position The position to get the left position of. + /// @return left_ The position to the left of `position`. + function left(Position _position) internal pure returns (Position left_) { + assembly { + left_ := shl(1, _position) + } + } + + /// @notice Get the right child of `_position` + /// @param _position The position to get the right position of. + /// @return right_ The position to the right of `position`. + function right(Position _position) internal pure returns (Position right_) { + assembly { + right_ := or(1, shl(1, _position)) + } + } + + /// @notice Get the parent position of `_position`. + /// @param _position The position to get the parent position of. + /// @return parent_ The parent position of `position`. + function parent(Position _position) internal pure returns (Position parent_) { + assembly { + parent_ := shr(1, _position) + } + } + + /// @notice Get the deepest, right most gindex relative to the `position`. This is equivalent to + /// calling `right` on a position until the maximum depth is reached. + /// @param _position The position to get the relative deepest, right most gindex of. + /// @param _maxDepth The maximum depth of the game. + /// @return rightIndex_ The deepest, right most gindex relative to the `position`. + function rightIndex(Position _position, uint256 _maxDepth) internal pure returns (Position rightIndex_) { + uint256 msb = depth(_position); + assembly { + let remaining := sub(_maxDepth, msb) + rightIndex_ := or(shl(remaining, _position), sub(shl(remaining, 1), 1)) + } + } + + /// @notice Get the deepest, right most trace index relative to the `position`. This is + /// equivalent to calling `right` on a position until the maximum depth is reached and + /// then finding its index at depth. + /// @param _position The position to get the relative trace index of. + /// @param _maxDepth The maximum depth of the game. + /// @return traceIndex_ The trace index relative to the `position`. + function traceIndex(Position _position, uint256 _maxDepth) internal pure returns (uint256 traceIndex_) { + uint256 msb = depth(_position); + assembly { + let remaining := sub(_maxDepth, msb) + traceIndex_ := sub(or(shl(remaining, _position), sub(shl(remaining, 1), 1)), shl(_maxDepth, 1)) + } + } + + /// @notice Gets the position of the highest ancestor of `_position` that commits to the same + /// trace index. + /// @param _position The position to get the highest ancestor of. + /// @return ancestor_ The highest ancestor of `position` that commits to the same trace index. + function traceAncestor(Position _position) internal pure returns (Position ancestor_) { + // Create a field with only the lowest unset bit of `_position` set. + Position lsb; + assembly { + lsb := and(not(_position), add(_position, 1)) + } + // Find the index of the lowest unset bit within the field. + uint256 msb = depth(lsb); + // The highest ancestor that commits to the same trace index is the original position + // shifted right by the index of the lowest unset bit. + assembly { + let a := shr(msb, _position) + // Bound the ancestor to the minimum gindex, 1. + ancestor_ := or(a, iszero(a)) + } + } + + /// @notice Gets the position of the highest ancestor of `_position` that commits to the same + /// trace index, while still being below `_upperBoundExclusive`. + /// @param _position The position to get the highest ancestor of. + /// @param _upperBoundExclusive The exclusive upper depth bound, used to inform where to stop in order + /// to not escape a sub-tree. + /// @return ancestor_ The highest ancestor of `position` that commits to the same trace index. + function traceAncestorBounded( + Position _position, + uint256 _upperBoundExclusive + ) + internal + pure + returns (Position ancestor_) + { + // This function only works for positions that are below the upper bound. + if (_position.depth() <= _upperBoundExclusive) { + assembly { + // Revert with `ClaimAboveSplit()` + mstore(0x00, 0xb34b5c22) + revert(0x1C, 0x04) + } + } + + // Grab the global trace ancestor. + ancestor_ = traceAncestor(_position); + + // If the ancestor is above or at the upper bound, shift it to be below the upper bound. + // This should be a special case that only covers positions that commit to the final leaf + // in a sub-tree. + if (ancestor_.depth() <= _upperBoundExclusive) { + ancestor_ = ancestor_.rightIndex(_upperBoundExclusive + 1); + } + } + + /// @notice Get the move position of `_position`, which is the left child of: + /// 1. `_position` if `_isAttack` is true. + /// 2. `_position | 1` if `_isAttack` is false. + /// @param _position The position to get the relative attack/defense position of. + /// @param _isAttack Whether or not the move is an attack move. + /// @return move_ The move position relative to `position`. + function move(Position _position, bool _isAttack) internal pure returns (Position move_) { + assembly { + move_ := shl(1, or(iszero(_isAttack), _position)) + } + } + + /// @notice Get the value of a `Position` type in the form of the underlying uint128. + /// @param _position The position to get the value of. + /// @return raw_ The value of the `position` as a uint128 type. + function raw(Position _position) internal pure returns (uint128 raw_) { + assembly { + raw_ := _position + } + } +} \ No newline at end of file diff --git a/op-verifier/contracts/lib/dispute/lib/LibUDT.sol b/op-verifier/contracts/lib/dispute/lib/LibUDT.sol new file mode 100644 index 00000000..2d2ee583 --- /dev/null +++ b/op-verifier/contracts/lib/dispute/lib/LibUDT.sol @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.15; + +import { Position } from "./LibPosition.sol"; + +using LibClaim for Claim global; +using LibHash for Hash global; +using LibDuration for Duration global; +using LibClock for Clock global; +using LibGameId for GameId global; +using LibTimestamp for Timestamp global; +using LibVMStatus for VMStatus global; +using LibGameType for GameType global; + +/// @notice A `Clock` represents a packed `Duration` and `Timestamp` +/// @dev The packed layout of this type is as follows: +/// ┌────────────┬────────────────┐ +/// │ Bits │ Value │ +/// ├────────────┼────────────────┤ +/// │ [0, 64) │ Duration │ +/// │ [64, 128) │ Timestamp │ +/// └────────────┴────────────────┘ +type Clock is uint128; + +/// @title LibClock +/// @notice This library contains helper functions for working with the `Clock` type. +library LibClock { + /// @notice Packs a `Duration` and `Timestamp` into a `Clock` type. + /// @param _duration The `Duration` to pack into the `Clock` type. + /// @param _timestamp The `Timestamp` to pack into the `Clock` type. + /// @return clock_ The `Clock` containing the `_duration` and `_timestamp`. + function wrap(Duration _duration, Timestamp _timestamp) internal pure returns (Clock clock_) { + assembly { + clock_ := or(shl(0x40, _duration), _timestamp) + } + } + + /// @notice Pull the `Duration` out of a `Clock` type. + /// @param _clock The `Clock` type to pull the `Duration` out of. + /// @return duration_ The `Duration` pulled out of `_clock`. + function duration(Clock _clock) internal pure returns (Duration duration_) { + // Shift the high-order 64 bits into the low-order 64 bits, leaving only the `duration`. + assembly { + duration_ := shr(0x40, _clock) + } + } + + /// @notice Pull the `Timestamp` out of a `Clock` type. + /// @param _clock The `Clock` type to pull the `Timestamp` out of. + /// @return timestamp_ The `Timestamp` pulled out of `_clock`. + function timestamp(Clock _clock) internal pure returns (Timestamp timestamp_) { + // Clean the high-order 192 bits by shifting the clock left and then right again, leaving + // only the `timestamp`. + assembly { + timestamp_ := shr(0xC0, shl(0xC0, _clock)) + } + } + + /// @notice Get the value of a `Clock` type in the form of the underlying uint128. + /// @param _clock The `Clock` type to get the value of. + /// @return clock_ The value of the `Clock` type as a uint128 type. + function raw(Clock _clock) internal pure returns (uint128 clock_) { + assembly { + clock_ := _clock + } + } +} + +/// @notice A `GameId` represents a packed 4 byte game ID, a 8 byte timestamp, and a 20 byte address. +/// @dev The packed layout of this type is as follows: +/// ┌───────────┬───────────┐ +/// │ Bits │ Value │ +/// ├───────────┼───────────┤ +/// │ [0, 32) │ Game Type │ +/// │ [32, 96) │ Timestamp │ +/// │ [96, 256) │ Address │ +/// └───────────┴───────────┘ +type GameId is bytes32; + +/// @title LibGameId +/// @notice Utility functions for packing and unpacking GameIds. +library LibGameId { + /// @notice Packs values into a 32 byte GameId type. + /// @param _gameType The game type. + /// @param _timestamp The timestamp of the game's creation. + /// @param _gameProxy The game proxy address. + /// @return gameId_ The packed GameId. + function pack( + GameType _gameType, + Timestamp _timestamp, + address _gameProxy + ) + internal + pure + returns (GameId gameId_) + { + assembly { + gameId_ := or(or(shl(224, _gameType), shl(160, _timestamp)), _gameProxy) + } + } + + /// @notice Unpacks values from a 32 byte GameId type. + /// @param _gameId The packed GameId. + /// @return gameType_ The game type. + /// @return timestamp_ The timestamp of the game's creation. + /// @return gameProxy_ The game proxy address. + function unpack(GameId _gameId) + internal + pure + returns (GameType gameType_, Timestamp timestamp_, address gameProxy_) + { + assembly { + gameType_ := shr(224, _gameId) + timestamp_ := and(shr(160, _gameId), 0xFFFFFFFFFFFFFFFF) + gameProxy_ := and(_gameId, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) + } + } +} + +/// @notice A claim represents an MPT root representing the state of the fault proof program. +type Claim is bytes32; + +/// @title LibClaim +/// @notice This library contains helper functions for working with the `Claim` type. +library LibClaim { + /// @notice Get the value of a `Claim` type in the form of the underlying bytes32. + /// @param _claim The `Claim` type to get the value of. + /// @return claim_ The value of the `Claim` type as a bytes32 type. + function raw(Claim _claim) internal pure returns (bytes32 claim_) { + assembly { + claim_ := _claim + } + } + + /// @notice Hashes a claim and a position together. + /// @param _claim A Claim type. + /// @param _position The position of `claim`. + /// @param _challengeIndex The index of the claim being moved against. + /// @return claimHash_ A hash of abi.encodePacked(claim, position|challengeIndex); + function hashClaimPos( + Claim _claim, + Position _position, + uint256 _challengeIndex + ) + internal + pure + returns (Hash claimHash_) + { + assembly { + mstore(0x00, _claim) + mstore(0x20, or(shl(128, _position), and(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, _challengeIndex))) + claimHash_ := keccak256(0x00, 0x40) + } + } +} + +/// @notice A dedicated duration type. +/// @dev Unit: seconds +type Duration is uint64; + +/// @title LibDuration +/// @notice This library contains helper functions for working with the `Duration` type. +library LibDuration { + /// @notice Get the value of a `Duration` type in the form of the underlying uint64. + /// @param _duration The `Duration` type to get the value of. + /// @return duration_ The value of the `Duration` type as a uint64 type. + function raw(Duration _duration) internal pure returns (uint64 duration_) { + assembly { + duration_ := _duration + } + } +} + +/// @notice A custom type for a generic hash. +type Hash is bytes32; + +/// @title LibHash +/// @notice This library contains helper functions for working with the `Hash` type. +library LibHash { + /// @notice Get the value of a `Hash` type in the form of the underlying bytes32. + /// @param _hash The `Hash` type to get the value of. + /// @return hash_ The value of the `Hash` type as a bytes32 type. + function raw(Hash _hash) internal pure returns (bytes32 hash_) { + assembly { + hash_ := _hash + } + } +} + +/// @notice A dedicated timestamp type. +type Timestamp is uint64; + +/// @title LibTimestamp +/// @notice This library contains helper functions for working with the `Timestamp` type. +library LibTimestamp { + /// @notice Get the value of a `Timestamp` type in the form of the underlying uint64. + /// @param _timestamp The `Timestamp` type to get the value of. + /// @return timestamp_ The value of the `Timestamp` type as a uint64 type. + function raw(Timestamp _timestamp) internal pure returns (uint64 timestamp_) { + assembly { + timestamp_ := _timestamp + } + } +} + +/// @notice A `VMStatus` represents the status of a VM execution. +type VMStatus is uint8; + +/// @title LibVMStatus +/// @notice This library contains helper functions for working with the `VMStatus` type. +library LibVMStatus { + /// @notice Get the value of a `VMStatus` type in the form of the underlying uint8. + /// @param _vmstatus The `VMStatus` type to get the value of. + /// @return vmstatus_ The value of the `VMStatus` type as a uint8 type. + function raw(VMStatus _vmstatus) internal pure returns (uint8 vmstatus_) { + assembly { + vmstatus_ := _vmstatus + } + } +} + +/// @notice A `GameType` represents the type of game being played. +type GameType is uint32; + +/// @title LibGameType +/// @notice This library contains helper functions for working with the `GameType` type. +library LibGameType { + /// @notice Get the value of a `GameType` type in the form of the underlying uint32. + /// @param _gametype The `GameType` type to get the value of. + /// @return gametype_ The value of the `GameType` type as a uint32 type. + function raw(GameType _gametype) internal pure returns (uint32 gametype_) { + assembly { + gametype_ := _gametype + } + } +} \ No newline at end of file diff --git a/op-verifier/contracts/lib/dispute/lib/Types.sol b/op-verifier/contracts/lib/dispute/lib/Types.sol new file mode 100644 index 00000000..0df5daa6 --- /dev/null +++ b/op-verifier/contracts/lib/dispute/lib/Types.sol @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.15; + +import { + Position, + Hash, + GameType, + VMStatus, + Timestamp, + Duration, + Clock, + GameId, + Claim, + LibGameId, + LibClock +} from "./LibUDT.sol"; + +/// @notice The current status of the dispute game. +enum GameStatus { + // The game is currently in progress, and has not been resolved. + IN_PROGRESS, + // The game has concluded, and the `rootClaim` was challenged successfully. + CHALLENGER_WINS, + // The game has concluded, and the `rootClaim` could not be contested. + DEFENDER_WINS +} + +/// @notice Represents an L2 output root and the L2 block number at which it was generated. +/// @custom:field root The output root. +/// @custom:field l2BlockNumber The L2 block number at which the output root was generated. +struct OutputRoot { + Hash root; + uint256 l2BlockNumber; +} + +/// @title GameTypes +/// @notice A library that defines the IDs of games that can be played. +library GameTypes { + /// @dev A dispute game type the uses the cannon vm. + GameType internal constant CANNON = GameType.wrap(0); + + /// @dev A permissioned dispute game type the uses the cannon vm. + GameType internal constant PERMISSIONED_CANNON = GameType.wrap(1); + + /// @notice A dispute game type the uses the asterisc VM + GameType internal constant ASTERISC = GameType.wrap(2); + + /// @notice A dispute game type with short game duration for testing withdrawals. + /// Not intended for production use. + GameType internal constant FAST = GameType.wrap(254); + + /// @notice A dispute game type that uses an alphabet vm. + /// Not intended for production use. + GameType internal constant ALPHABET = GameType.wrap(255); +} + +/// @title VMStatuses +/// @notice Named type aliases for the various valid VM status bytes. +library VMStatuses { + /// @notice The VM has executed successfully and the outcome is valid. + VMStatus internal constant VALID = VMStatus.wrap(0); + + /// @notice The VM has executed successfully and the outcome is invalid. + VMStatus internal constant INVALID = VMStatus.wrap(1); + + /// @notice The VM has paniced. + VMStatus internal constant PANIC = VMStatus.wrap(2); + + /// @notice The VM execution is still in progress. + VMStatus internal constant UNFINISHED = VMStatus.wrap(3); +} + +/// @title LocalPreimageKey +/// @notice Named type aliases for local `PreimageOracle` key identifiers. +library LocalPreimageKey { + /// @notice The identifier for the L1 head hash. + uint256 internal constant L1_HEAD_HASH = 0x01; + + /// @notice The identifier for the starting output root. + uint256 internal constant STARTING_OUTPUT_ROOT = 0x02; + + /// @notice The identifier for the disputed output root. + uint256 internal constant DISPUTED_OUTPUT_ROOT = 0x03; + + /// @notice The identifier for the disputed L2 block number. + uint256 internal constant DISPUTED_L2_BLOCK_NUMBER = 0x04; + + /// @notice The identifier for the chain ID. + uint256 internal constant CHAIN_ID = 0x05; +} \ No newline at end of file diff --git a/op-verifier/deploy_l1/00_op_verifier.ts b/op-verifier/deploy_l1/00_op_verifier.ts index f2af7982..d81edec9 100644 --- a/op-verifier/deploy_l1/00_op_verifier.ts +++ b/op-verifier/deploy_l1/00_op_verifier.ts @@ -2,35 +2,26 @@ import {HardhatRuntimeEnvironment} from 'hardhat/types'; import {DeployFunction} from 'hardhat-deploy/types'; import fs from 'fs'; -const GATEWAY_URLS = { - 'opDevnetL1':'http://localhost:8080/{sender}/{data}.json', - 'goerli':'https://op-gateway-worker.ens-cf.workers.dev/{sender}/{data}.json', - 'sepolia':'https://op-sepolia-gateway-worker.ens-cf.workers.dev/{sender}/{data}.json', - 'sepoliaForBase':'https://base-sepolia-gateway-worker.ens-cf.workers.dev/{sender}/{data}.json', -} - -const L2_OUTPUT_ORACLE_ADDRESSES = { - 'goerli': '0xE6Dfba0953616Bacab0c9A8ecb3a9BBa77FC15c0', - 'sepolia': '0x90E9c4f8a994a250F6aEfd61CAFb4F2e895D458F', - 'sepoliaForBase': '0x84457ca9D0163FbC4bbfe4Dfbb20ba46e48DF254', -} - const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { const {deployments, getNamedAccounts, network} = hre; const {deploy} = deployments; const {deployer} = await getNamedAccounts(); - let L2_OUTPUT_ORACLE_ADDRESS, GATEWAY_URL + + // https://op-gateway-worker.ens-cf.workers.dev/{sender}/{data}.json + let GATEWAY_URL = process.env.GATEWAY_URL + let OPTIMISM_PORTAL_ADDRESS = process.env.OPTIMISM_PORTAL_ADDRESS + let MINIMUM_AGE = parseInt(process.env.MINIMUM_AGE || '60') + let MAXIMUM_AGE = parseInt(process.env.MAXIMUM_AGE || '1209600') + if(network.name === 'opDevnetL1'){ const opAddresses = await (await fetch("http://localhost:8080/addresses.json")).json(); - L2_OUTPUT_ORACLE_ADDRESS = opAddresses.L2OutputOracleProxy - }else{ - GATEWAY_URL = GATEWAY_URLS[network.name] - L2_OUTPUT_ORACLE_ADDRESS = L2_OUTPUT_ORACLE_ADDRESSES[network.name] + OPTIMISM_PORTAL_ADDRESS = opAddresses.OptimismPortalProxy } - console.log('OPVerifier', [[GATEWAY_URL], L2_OUTPUT_ORACLE_ADDRESS]) + + console.log('OPVerifier', [[GATEWAY_URL], OPTIMISM_PORTAL_ADDRESS, MINIMUM_AGE, MAXIMUM_AGE]) await deploy('OPVerifier', { from: deployer, - args: [[GATEWAY_URL], L2_OUTPUT_ORACLE_ADDRESS], + args: [[GATEWAY_URL], OPTIMISM_PORTAL_ADDRESS, MINIMUM_AGE, MAXIMUM_AGE], log: true, }); }; diff --git a/op-verifier/deploy_l1/01_op_output_lookup.ts b/op-verifier/deploy_l1/01_op_output_lookup.ts new file mode 100644 index 00000000..7dcf5e88 --- /dev/null +++ b/op-verifier/deploy_l1/01_op_output_lookup.ts @@ -0,0 +1,18 @@ +import {HardhatRuntimeEnvironment} from 'hardhat/types'; +import {DeployFunction} from 'hardhat-deploy/types'; +import fs from 'fs'; + +const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { + const {deployments, getNamedAccounts, network} = hre; + const {deploy} = deployments; + const {deployer} = await getNamedAccounts(); + + await deploy('OPOutputLookup', { + from: deployer, + args: [], + log: true, + deterministicDeployment: '0x0000000000000000000000000000000000000000000000000000000000000000', + }); +}; +export default func; +func.tags = ['OPOutputLookup']; diff --git a/op-verifier/hardhat.config.ts b/op-verifier/hardhat.config.ts index 4f93ecc4..ecdb0869 100644 --- a/op-verifier/hardhat.config.ts +++ b/op-verifier/hardhat.config.ts @@ -9,7 +9,19 @@ const L1_ETHERSCAN_API_KEY = process.env.L1_ETHERSCAN_API_KEY; const L2_ETHERSCAN_API_KEY = process.env.L2_ETHERSCAN_API_KEY; const config: HardhatUserConfig = { - solidity: '0.8.19', + solidity: { + compilers: [ + { + version: '0.8.26', + settings: { + optimizer: { + enabled: true, + runs: 200 + } + } + }, + ] + }, networks: { opDevnetL1: { url: "http://localhost:8545/", @@ -66,12 +78,12 @@ const config: HardhatUserConfig = { }, etherscan: { apiKey: { - goerli: L1_ETHERSCAN_API_KEY, - sepolia: L1_ETHERSCAN_API_KEY, - optimismGoerli: L2_ETHERSCAN_API_KEY, - baseGoerli: L2_ETHERSCAN_API_KEY, - optimismSepolia: L2_ETHERSCAN_API_KEY, - baseSepolia: L2_ETHERSCAN_API_KEY, + goerli: L1_ETHERSCAN_API_KEY || '', + sepolia: L1_ETHERSCAN_API_KEY || '', + optimismGoerli: L2_ETHERSCAN_API_KEY || '', + baseGoerli: L2_ETHERSCAN_API_KEY || '', + optimismSepolia: L2_ETHERSCAN_API_KEY || '', + baseSepolia: L2_ETHERSCAN_API_KEY || '', }, customChains: [ { diff --git a/op-verifier/package.json b/op-verifier/package.json index e4de99e5..b1e504ec 100644 --- a/op-verifier/package.json +++ b/op-verifier/package.json @@ -4,9 +4,10 @@ "version": "0.1.0", "scripts": { "build": "echo 'building op-verifier...' && bun hardhat compile", - "test": "echo hardhat test", + "test": "bun hardhat test", "clean": "rm -fr artifacts cache node_modules typechain-types", - "lint": "exit 0" + "lint": "exit 0", + "postinstall": "find node_modules/src/src -mindepth 1 -maxdepth 1 -exec basename {} \\; | xargs -I {} sh -c 'rm -rf node_modules/src/{}; ln -s src/{} node_modules/src/{}'" }, "devDependencies": { "@ensdomains/op-gateway": "workspace:*", @@ -26,8 +27,8 @@ "express": "^4.18.2", "ganache": "^7.9.1", "hardhat": "^2.16.0", - "hardhat-deploy": "^0.11.43", - "hardhat-deploy-ethers": "^0.4.1", + "hardhat-deploy": "^0.12.4", + "hardhat-deploy-ethers": "^0.4.2", "hardhat-gas-reporter": "^1.0.8", "solidity-bytes-utils": "^0.8.0", "solidity-coverage": "^0.8.1", @@ -37,8 +38,8 @@ "typescript": "^5.2.2" }, "dependencies": { - "@ensdomains/evm-verifier": "0.1.0-beta.4", + "@ensdomains/evm-verifier": "workspace:*", "@eth-optimism/contracts": "^0.6.0", - "@eth-optimism/contracts-bedrock": "^0.16.2" + "src": "npm:@eth-optimism/contracts-bedrock@0.17.3" } } diff --git a/op-verifier/test/testOPVerifier.ts b/op-verifier/test/testOPVerifier.ts index 4c9be367..ed8705f7 100644 --- a/op-verifier/test/testOPVerifier.ts +++ b/op-verifier/test/testOPVerifier.ts @@ -34,7 +34,6 @@ declare module 'hardhat/types/runtime' { describe('OPVerifier', () => { let provider: Provider; let signer: Signer; - let gateway: express.Application; let target: Contract; before(async () => { @@ -43,12 +42,17 @@ describe('OPVerifier', () => { provider = new ethers.BrowserProvider(hre.network.provider); signer = await provider.getSigner(0); - const opAddresses = await (await fetch("http://localhost:8080/addresses.json")).json(); + let optimismPortalAddress = process.env.OPTIMISM_PORTAL_ADDRESS! + + if (hre.network.name == 'opDevnetL1') { + const opAddresses = await (await fetch("http://localhost:8080/addresses.json")).json(); + optimismPortalAddress = opAddresses.OptimismPortalProxy + } const gateway = await makeOPGateway( (hre.network.config as any).url, (hre.config.networks[hre.network.companionNetworks.l2] as any).url, - opAddresses.L2OutputOracleProxy, + optimismPortalAddress, 5, ); const server = new Server() diff --git a/package.json b/package.json index 78309488..e939eb1a 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ }, "dependencies": { "@ensdomains/ccip-read-cf-worker": "^0.0.3", - "@eth-optimism/sdk": "^3.1.4" + "@eth-optimism/sdk": "^3.1.4", + "aws-lambda": "^1.0.7" } } diff --git a/scroll-gateway/package.json b/scroll-gateway/package.json index e9e426e9..607199ef 100644 --- a/scroll-gateway/package.json +++ b/scroll-gateway/package.json @@ -57,7 +57,7 @@ }, "dependencies": { "@chainlink/ccip-read-server": "^0.2.1", - "@ensdomains/evm-gateway": "0.1.0-beta.4", + "@ensdomains/evm-gateway": "workspace:*", "@ethereumjs/block": "^5.0.0", "@nomicfoundation/ethereumjs-block": "^5.0.2", "commander": "^11.0.0", diff --git a/scroll-verifier/package.json b/scroll-verifier/package.json index 0f694007..8eca7512 100644 --- a/scroll-verifier/package.json +++ b/scroll-verifier/package.json @@ -37,7 +37,7 @@ "typescript": "^5.2.2" }, "dependencies": { - "@ensdomains/evm-verifier": "0.1.0-beta.4", + "@ensdomains/evm-verifier": "workspace:*", "dotenv": "^16.3.1" } }