diff --git a/.github/workflows/gasreport.yml b/.github/workflows/gasreport.yml new file mode 100644 index 0000000000..bee09623c9 --- /dev/null +++ b/.github/workflows/gasreport.yml @@ -0,0 +1,37 @@ +# .github/workflows/gasreport.yml +name: Gas report + +on: + pull_request: + paths: + - packages/store/** + +jobs: + gas-report: + runs-on: ubuntu-22.04 + name: Generate gas report + steps: + - uses: actions/setup-node@v3 + with: + node-version: 16 + + - name: git-checkout + uses: actions/checkout@v3 + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: nightly + + - name: Install dependencies + run: yarn install --network-concurrency 1 + + - name: Install local CLI + run: cd packages/cli && yarn build && npm link && cd ../.. + + - name: Run gas report + run: yarn workspace @latticexyz/store run gasreport + + - uses: stefanzweifel/git-auto-commit-action@v4 + with: + commit_message: "test: update gas report" diff --git a/package.json b/package.json index 278a442505..9e4865824f 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "packages": [ "packages/utils", "packages/solecs", + "packages/store", "packages/cli", "packages/recs", "packages/react", diff --git a/packages/cli/package.json b/packages/cli/package.json index bcab9c02d6..56fcafd2c2 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -63,6 +63,7 @@ "openurl": "^1.1.1", "path": "^0.12.7", "solmate": "https://github.com/Rari-Capital/solmate.git#9cf1428245074e39090dceacb0c28b1f684f584c", + "table": "^6.8.1", "typechain": "^8.1.1", "uuid": "^8.3.2", "yargs": "^17.5.1" diff --git a/packages/cli/src/commands/gas-report.ts b/packages/cli/src/commands/gas-report.ts new file mode 100644 index 0000000000..f66c23a4e1 --- /dev/null +++ b/packages/cli/src/commands/gas-report.ts @@ -0,0 +1,219 @@ +import type { Arguments, CommandBuilder } from "yargs"; +import { readFileSync, writeFileSync, rmSync } from "fs"; +import { execa } from "execa"; +import chalk from "chalk"; +import { table, getBorderCharacters } from "table"; + +/** + * Print the gas report to the console, save it to a file and compare it to a previous gas report if provided. + * Requires forge to be installed, and gas test files including `// !gasreport` comments, like this: + * + * ```solidity + * contract GasTest is DSTestPlus { + * function testBuffer() public pure { + * // !gasreport allocate a buffer + * Buffer buffer = Buffer_.allocate(32); + * + * bytes32 value = keccak256("some data"); + * + * // !gasreport append 32 bytes to a buffer + * buffer.append(value); + * } + * } + * ``` + */ + +type Options = { + path: string[]; + save?: string; + compare?: string; +}; + +type GasReportEntry = { + source: string; + name: string; + functionCall: string; + gasUsed: number; + prevGasUsed?: number; +}; + +type GasReport = GasReportEntry[]; + +export const command = "gas-report"; +export const desc = "Create a gas report"; + +export const builder: CommandBuilder = (yargs) => + yargs.options({ + path: { type: "array", default: ["Gas.t.sol"], desc: "File containing the gas tests" }, + save: { type: "string", desc: "Save the gas report to a file" }, + compare: { type: "string", desc: "Compare to an existing gas report" }, + }); + +export const handler = async (args: Arguments): Promise => { + const { path, save } = args; + let { compare } = args; + let gasReport: GasReport = []; + + // Iterate through all files provided in the path + for (const file of path) { + gasReport = gasReport.concat(await runGasReport(file)); + } + + // If this gas report should be compared to an existing one, load the existing one + const compareGasReport: GasReport = []; + if (compare) { + try { + const compareFileContents = readFileSync(compare, "utf8"); + // Create a regex to extract the name, function call and gas used + const compareGasReportRegex = new RegExp(/\((.*)\) \| (.*) \[(.*)\]: (.*)/g); + // Loop through the matches and add the resuls to the compareGasReport + let compareGasReportMatch; + while ((compareGasReportMatch = compareGasReportRegex.exec(compareFileContents)) !== null) { + const source = compareGasReportMatch[1]; + const name = compareGasReportMatch[2]; + const functionCall = compareGasReportMatch[3]; + const gasUsed = compareGasReportMatch[4]; + + compareGasReport.push({ source, name, functionCall, gasUsed: parseInt(gasUsed) }); + } + } catch { + console.log(chalk.red(`Gas report to compare not found: ${compare}`)); + compare = undefined; + } + } + + // Merge the previous gas report with the new one + gasReport = gasReport.map((entry) => { + const prevEntry = compareGasReport.find((e) => e.name === entry.name && e.functionCall === entry.functionCall); + return { ...entry, prevGasUsed: prevEntry?.gasUsed }; + }); + + // Print gas report + printGasReport(gasReport, compare); + + // Save gas report to file if requested + if (save) saveGasReport(gasReport, save); + + process.exit(0); +}; + +async function runGasReport(path: string): Promise { + if (!path.endsWith(".t.sol")) { + console.log("Skipping gas report for", chalk.bold(path), "(not a test file)"); + return []; + } + console.log("Running gas report for", chalk.bold(path)); + const gasReport: GasReport = []; + + // Parse the given test file, and add gas reporting wherever requested by a `// !gasreport` comment + const fileContents = readFileSync(path, "utf8"); + let newFile = fileContents; + + // Use a regex to find first line of each function + const functionRegex = new RegExp(/function (.*){/g); + // Insert a line to declare the _gasreport variable at the start of each function + let functionMatch; + while ((functionMatch = functionRegex.exec(fileContents)) !== null) { + const functionSignature = functionMatch[0]; + newFile = newFile.replace(functionSignature, `${functionSignature}\nuint256 _gasreport;`); + } + + // A gasreport comment has a name (written after the comment) and a function call (written on the next line) + // Create a regex to extract both the name and the function call + const regex = new RegExp(/\/\/ !gasreport (.*)\n(.*)/g); + + // Apply the regex and loop through the matches, + // and create a new file with the gasreport comments replaced by the gas report + let match; + let i = 0; + while ((match = regex.exec(fileContents)) !== null) { + const name = match[1]; + const functionCall = match[2].trim(); + + newFile = newFile.replace( + match[0], + ` +_gasreport = gasleft(); +${functionCall} +_gasreport = _gasreport - gasleft(); +console.log("GAS REPORT: ${name} [${functionCall.replaceAll('"', '\\"')}]:", _gasreport);` + ); + + i++; + } + + // Remove all occurrences of `pure` with `view` + newFile = newFile.replace(/pure/g, "view"); + + // Write the new file to disk (temporarily) + // Create the temp file by replacing the previous file name with MudGasReport + const tempFileName = path.replace(/\.t\.sol$/, "MudGasReport.t.sol"); + writeFileSync(tempFileName, newFile); + + // Run the generated file using forge + const child = execa("forge", ["test", "--match-path", tempFileName, "-vvv"], { + stdio: ["inherit", "pipe", "inherit"], + }); + + // Extrect the logs from the child process + let logs = ""; + try { + logs = (await child).stdout; + rmSync(tempFileName); + } catch (e: any) { + console.log(e.stdout ?? e); + console.log(chalk.red("\n-----------\nError while running the gas report (see above)")); + rmSync(tempFileName); + process.exit(); + } + + // Extract the gas reports from the logs + + // Create a regex to find all lines starting with `GAS REPORT:` and extract the name, function call and gas used + const gasReportRegex = new RegExp(/GAS REPORT: (.*) \[(.*)\]: (.*)/g); + + // Loop through the matches and print the gas report + let gasReportMatch; + while ((gasReportMatch = gasReportRegex.exec(logs)) !== null) { + const name = gasReportMatch[1]; + const functionCall = gasReportMatch[2].replace(";", ""); + const gasUsed = gasReportMatch[3]; + + gasReport.push({ source: path, name, functionCall, gasUsed: parseInt(gasUsed) }); + } + + return gasReport; +} + +function printGasReport(gasReport: GasReport, compare?: string) { + if (compare) console.log(chalk.bold(`Gas report compared to ${compare}`)); + + const headers = [ + chalk.bold("Source"), + chalk.bold("Name"), + chalk.bold("Function call"), + chalk.bold("Gas used"), + ...(compare ? [chalk.bold("Prev gas used"), chalk.bold("Difference")] : []), + ]; + + const values = gasReport.map((entry) => { + const diff = entry.prevGasUsed ? entry.gasUsed - entry.prevGasUsed : 0; + const diffEntry = diff > 0 ? chalk.red(`+${diff}`) : diff < 0 ? chalk.green(`${diff}`) : diff; + const compareColumns = compare ? [entry.prevGasUsed ?? "n/a", diffEntry] : []; + const gasUsedEntry = diff > 0 ? chalk.red(entry.gasUsed) : diff < 0 ? chalk.green(entry.gasUsed) : entry.gasUsed; + return [entry.source, entry.name, entry.functionCall, gasUsedEntry, ...compareColumns]; + }); + + const rows = [headers, ...values]; + + console.log(table(rows, { border: getBorderCharacters("norc") })); +} + +function saveGasReport(gasReport: GasReport, path: string) { + console.log(chalk.bold(`Saving gas report to ${path}`)); + const serializedGasReport = gasReport + .map((entry) => `(${entry.source}) | ${entry.name} [${entry.functionCall}]: ${entry.gasUsed}`) + .join("\n"); + + writeFileSync(path, serializedGasReport); +} diff --git a/packages/cli/tsconfig.json b/packages/cli/tsconfig.json index df5a65239a..5a15b828a1 100644 --- a/packages/cli/tsconfig.json +++ b/packages/cli/tsconfig.json @@ -11,7 +11,7 @@ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ /* Language and Environment */ - "target": "es2015" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + "target": "es2021" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ // "jsx": "preserve", /* Specify what JSX code is generated. */ // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ diff --git a/packages/store/.gitignore b/packages/store/.gitignore new file mode 100644 index 0000000000..2f6f3adfc2 --- /dev/null +++ b/packages/store/.gitignore @@ -0,0 +1,10 @@ +cache +abi +out +types/ethers-contracts +docs +_docs +DOCS.md +artifacts +yarn-error.log +API \ No newline at end of file diff --git a/packages/store/.npmignore b/packages/store/.npmignore new file mode 100644 index 0000000000..4240dbeb28 --- /dev/null +++ b/packages/store/.npmignore @@ -0,0 +1,7 @@ +* + +!abi/** +!src/** +!types/** +!package.json +!README.md \ No newline at end of file diff --git a/packages/store/.nvmrc b/packages/store/.nvmrc new file mode 100644 index 0000000000..8e2afd3427 --- /dev/null +++ b/packages/store/.nvmrc @@ -0,0 +1 @@ +17 \ No newline at end of file diff --git a/packages/store/.prettierrc b/packages/store/.prettierrc new file mode 100644 index 0000000000..9a5a009900 --- /dev/null +++ b/packages/store/.prettierrc @@ -0,0 +1,7 @@ +{ + "printWidth": 120, + "semi": true, + "tabWidth": 2, + "useTabs": false, + "bracketSpacing": true +} diff --git a/packages/store/.solhint.json b/packages/store/.solhint.json new file mode 100644 index 0000000000..4e2baa8be7 --- /dev/null +++ b/packages/store/.solhint.json @@ -0,0 +1,8 @@ +{ + "extends": "solhint:recommended", + "rules": { + "compiler-version": ["error", ">=0.8.0"], + "avoid-low-level-calls": "off", + "func-visibility": ["warn", { "ignoreConstructors": true }] + } +} diff --git a/packages/store/CHANGELOG.md b/packages/store/CHANGELOG.md new file mode 100644 index 0000000000..e4d87c4d45 --- /dev/null +++ b/packages/store/CHANGELOG.md @@ -0,0 +1,4 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. diff --git a/packages/store/CHANGELOG.yml b/packages/store/CHANGELOG.yml new file mode 100644 index 0000000000..e3f6e391b4 --- /dev/null +++ b/packages/store/CHANGELOG.yml @@ -0,0 +1 @@ +label: Changelog diff --git a/packages/store/README.md b/packages/store/README.md new file mode 100644 index 0000000000..3f8815b136 --- /dev/null +++ b/packages/store/README.md @@ -0,0 +1 @@ +# Store diff --git a/packages/store/foundry.toml b/packages/store/foundry.toml new file mode 100644 index 0000000000..4e1a99ebba --- /dev/null +++ b/packages/store/foundry.toml @@ -0,0 +1,9 @@ +[profile.default] +ffi = false +fuzz_runs = 256 +optimizer = true +optimizer_runs = 1000000 +verbosity = 1 +libs = ["../../node_modules"] +src = "src" +out = "out" \ No newline at end of file diff --git a/packages/store/gas-report.txt b/packages/store/gas-report.txt new file mode 100644 index 0000000000..8f1b868e45 --- /dev/null +++ b/packages/store/gas-report.txt @@ -0,0 +1,112 @@ +(test/Buffer.t.sol) | allocate a buffer [Buffer buf = Buffer_.allocate(32)]: 73 +(test/Buffer.t.sol) | get buffer length [buf.length()]: 87 +(test/Buffer.t.sol) | get buffer pointer [buf.ptr()]: 33 +(test/Buffer.t.sol) | get buffer capacity [buf.capacity()]: 7 +(test/Buffer.t.sol) | append unchecked bytes memory (8) to buffer [buf.appendUnchecked(data1)]: 478 +(test/Buffer.t.sol) | append bytes memory (8) to buffer [buf.append(data2)]: 773 +(test/Buffer.t.sol) | append unchecked bytes8 of bytes32 to buffer [buf.appendUnchecked(data1, 8)]: 351 +(test/Buffer.t.sol) | append bytes8 of bytes32 to buffer [buf.append(data2, 8)]: 645 +(test/Buffer.t.sol) | concat 3 bytes memory (32) using buffer [Buffer buf = Buffer_.concat(data1, data2, data3)]: 2638 +(test/Buffer.t.sol) | concat 3 bytes memory (32) using bytes.concat [bytes memory concat = bytes.concat(data1, data2, data3)]: 641 +(test/Buffer.t.sol) | concat 3 bytes memory (32) using abi.encodePacked [bytes memory concat2 = abi.encodePacked(data1, data2, data3)]: 641 +(test/Buffer.t.sol) | create a buffer from 8 bytes [Buffer buf = Buffer_.fromBytes(data)]: 40 +(test/Buffer.t.sol) | read bytes32 from buffer [bytes32 value = buf.read32(4)]: 102 +(test/Buffer.t.sol) | read bytes8 with offset 3 from buffer [bytes8 value2 = buf.read8(3)]: 151 +(test/Buffer.t.sol) | read bytes1 with offset 7 from buffer [bytes1 value3 = buf.read1(7)]: 151 +(test/Buffer.t.sol) | set buffer length unchecked [buf._setLengthUnchecked(8)]: 86 +(test/Buffer.t.sol) | set buffer length [buf._setLength(16)]: 192 +(test/Buffer.t.sol) | slice 4 bytes from buffer with offset 4 [bytes memory slice = buf.slice(4, 4)]: 635 +(test/Buffer.t.sol) | convert array pointer to uint256[] [uint256[] memory arr = Cast.toUint256Array(arrayPtr)]: 10 +(test/Buffer.t.sol) | buffer toArray with element length 4 [uint256 arrayPtr = buf.toArray(4)]: 745 +(test/Buffer.t.sol) | convert array pointer to uint32[] [uint32[] memory arr = Cast.toUint32Array(arrayPtr)]: 10 +(test/Buffer.t.sol) | buffer (32 bytes) to bytes memory [bytes memory bufferData = buf.toBytes()]: 90 +(test/Bytes.t.sol) | compare equal bytes [bool equals = Bytes.equals(a, b)]: 202 +(test/Bytes.t.sol) | compare unequal bytes [bool equals = Bytes.equals(a, b)]: 202 +(test/Bytes.t.sol) | create uint32 array from bytes memory [uint32[] memory output = Bytes.toUint32Array(tight)]: 835 +(test/Bytes.t.sol) | create bytes from bytes array [bytes memory output = Bytes.from(input)]: 1290 +(test/Bytes.t.sol) | create bytes from uint16 array [bytes memory output = Bytes.from(input)]: 791 +(test/Bytes.t.sol) | create bytes from uint32 array [bytes memory output = Bytes.from(input)]: 695 +(test/Bytes.t.sol) | create bytes from uint8 array [bytes memory output = Bytes.from(input)]: 695 +(test/Bytes.t.sol) | set bytes1 in bytes32 [Bytes.setBytes1(input, 8, 0xff)]: 7 +(test/Bytes.t.sol) | set bytes2 in bytes32 [Bytes.setBytes2(input, 8, 0xffff)]: 7 +(test/Bytes.t.sol) | set bytes4 in bytes32 [Bytes.setBytes4(input, 8, 0xffffffff)]: 7 +(test/Bytes.t.sol) | slice bytes (with copying) with offset 1 and length 3 [bytes memory b = Bytes.slice(a, 1, 3)]: 516 +(test/Bytes.t.sol) | slice bytes3 with offset 1 [bytes3 b = Bytes.slice3(a, 1)]: 77 +(test/Bytes.t.sol) | slice bytes32 with offset 10 [bytes32 output = Bytes.slice32(input, 10)]: 74 +(test/Bytes.t.sol) | tightly pack bytes24 array into bytes array [bytes memory tight = Bytes.from(input)]: 477 +(test/Bytes.t.sol) | create uint32 array from bytes memory [bytes24[] memory output = Bytes.toBytes24Array(tight)]: 614 +(test/Bytes.t.sol) | create bytes32 from bytes memory with offset 0 [bytes32 output = Bytes.toBytes32(input, 0)]: 22 +(test/Bytes.t.sol) | create bytes32 array from bytes memory [bytes32[] memory output = Bytes.toBytes32Array(input)]: 1110 +(test/Bytes.t.sol) | create bytes32 array from bytes memory with uneven length [bytes32[] memory output = Bytes.toBytes32Array(input)]: 1425 +(test/Bytes.t.sol) | create bytes32 from bytes memory with offset 16 [bytes32 output = Bytes.toBytes32(input, 16)]: 22 +(test/Gas.t.sol) | abi encode [bytes memory abiEncoded = abi.encode(mixed)]: 930 +(test/Gas.t.sol) | abi decode [Mixed memory abiDecoded = abi.decode(abiEncoded, (Mixed))]: 1713 +(test/Gas.t.sol) | custom encode [bytes memory customEncoded = customEncode(mixed)]: 1393 +(test/Gas.t.sol) | custom decode [Mixed memory customDecoded = customDecode(customEncoded)]: 2772 +(test/Gas.t.sol) | pass abi encoded bytes to external contract [someContract.doSomethingWithBytes(abiEncoded)]: 6537 +(test/Gas.t.sol) | pass custom encoded bytes to external contract [someContract.doSomethingWithBytes(customEncoded)]: 1342 +(test/MixedTable.t.sol) | store Mixed struct in storage (native solidity) [testMixed = mixed]: 92016 +(test/MixedTable.t.sol) | register MixedTable schema [MixedTable.registerSchema()]: 32496 +(test/MixedTable.t.sol) | set record in MixedTable [MixedTable.set({ key: key, u32: 1, u128: 2, a32: a32, s: s })]: 114455 +(test/MixedTable.t.sol) | get record from MixedTable [Mixed memory mixed = MixedTable.get(key)]: 20471 +(test/PackedCounter.t.sol) | get value at index of PackedCounter [packedCounter.atIndex(3)]: 272 +(test/PackedCounter.t.sol) | set value at index of PackedCounter [packedCounter = packedCounter.setAtIndex(2, 5)]: 830 +(test/PackedCounter.t.sol) | pack uint16 array into PackedCounter [PackedCounter packedCounter = PackedCounterLib.pack(counters)]: 2148 +(test/PackedCounter.t.sol) | get total of PackedCounter [packedCounter.total()]: 33 +(test/RouteTable.t.sol) | register RouteTable schema [RouteTable.registerSchema()]: 30440 +(test/RouteTable.t.sol) | set RouteTable record [RouteTable.set(key, addr, selector, executionMode)]: 35240 +(test/RouteTable.t.sol) | get RouteTable record [Route memory systemEntry = RouteTable.get(key)]: 6554 +(test/Schema.t.sol) | encode schema with 6 entries [SchemaLib.encode]: 6172 +(test/Schema.t.sol) | get schema type at index [SchemaType schemaType1 = schema.atIndex(0)]: 200 +(test/Schema.t.sol) | get number of dynamic fields from schema [uint256 num = schema.numDynamicFields()]: 80 +(test/Schema.t.sol) | get number of static fields from schema [uint256 num = schema.numStaticFields()]: 91 +(test/Schema.t.sol) | get static data length from schema [uint256 length = schema.staticDataLength()]: 39 +(test/Schema.t.sol) | check if schema is empty (non-empty schema) [bool empty = encodedSchema.isEmpty()]: 13 +(test/Schema.t.sol) | check if schema is empty (empty schema) [bool empty = encodedSchema.isEmpty()]: 13 +(test/Schema.t.sol) | validate schema [encodedSchema.validate()]: 22716 +(test/Storage.t.sol) | store 1 storage slot [Storage.store({ storagePointer: storagePointer, data: originalDataFirstSlot })]: 23449 +(test/Storage.t.sol) | store 34 bytes over 3 storage slots (with offset and safeTrail)) [Storage.store({ storagePointer: storagePointer, offset: 31, data: data1 })]: 25604 +(test/Storage.t.sol) | load 34 bytes over 3 storage slots (with offset and safeTrail)) [bytes memory data = Storage.load({ storagePointer: storagePointer, length: 34, offset: 31 })]: 4131 +(test/StoreCore.t.sol) | access non-existing record [bytes memory data1 = StoreCore.getRecord(table, key)]: 10090 +(test/StoreCore.t.sol) | access static field of non-existing record [bytes memory data2 = StoreCore.getField(table, key, 0)]: 4505 +(test/StoreCore.t.sol) | access dynamic field of non-existing record [bytes memory data3 = StoreCore.getField(table, key, 1)]: 3940 +(test/StoreCore.t.sol) | delete record (complex data, 3 slots) [StoreCore.deleteRecord(table, key)]: 10970 +(test/StoreCore.t.sol) | Check for existence of table (existent) [StoreCore.hasTable(table)]: 992 +(test/StoreCore.t.sol) | check for existence of table (non-existent) [StoreCore.hasTable(table2)]: 2993 +(test/StoreCore.t.sol) | register subscriber [StoreCore.registerHook(table, subscriber)]: 70323 +(test/StoreCore.t.sol) | set record on table with subscriber [StoreCore.setRecord(table, key, data)]: 72168 +(test/StoreCore.t.sol) | set static field on table with subscriber [StoreCore.setField(table, key, 0, data)]: 34254 +(test/StoreCore.t.sol) | delete record on table with subscriber [StoreCore.deleteRecord(table, key)]: 24678 +(test/StoreCore.t.sol) | register subscriber [StoreCore.registerHook(table, subscriber)]: 70323 +(test/StoreCore.t.sol) | set (dynamic) record on table with subscriber [StoreCore.setRecord(table, key, data)]: 174918 +(test/StoreCore.t.sol) | set (dynamic) field on table with subscriber [StoreCore.setField(table, key, 1, arrayDataBytes)]: 37025 +(test/StoreCore.t.sol) | delete (dynamic) record on table with subscriber [StoreCore.deleteRecord(table, key)]: 30425 +(test/StoreCore.t.sol) | StoreCore: register schema [StoreCore.registerSchema(table, schema)]: 26419 +(test/StoreCore.t.sol) | StoreCore: get schema (warm) [Schema loadedSchema = StoreCore.getSchema(table)]: 937 +(test/StoreCore.t.sol) | set complex record with dynamic data (4 slots) [StoreCore.setRecord(table, key, data)]: 110652 +(test/StoreCore.t.sol) | get complex record with dynamic data (4 slots) [bytes memory loadedData = StoreCore.getRecord(table, key)]: 12755 +(test/StoreCore.t.sol) | compare: Set complex record with dynamic data using native solidity [testStruct = _testStruct]: 116815 +(test/StoreCore.t.sol) | compare: Set complex record with dynamic data using abi.encode [testMapping[1234] = abi.encode(_testStruct)]: 267529 +(test/StoreCore.t.sol) | set dynamic length of dynamic index 0 [StoreCoreInternal._setDynamicDataLengthAtIndex(table, key, 0, 10)]: 23676 +(test/StoreCore.t.sol) | set dynamic length of dynamic index 1 [StoreCoreInternal._setDynamicDataLengthAtIndex(table, key, 1, 99)]: 1777 +(test/StoreCore.t.sol) | reduce dynamic length of dynamic index 0 [StoreCoreInternal._setDynamicDataLengthAtIndex(table, key, 0, 5)]: 1768 +(test/StoreCore.t.sol) | set static field (1 slot) [StoreCore.setField(table, key, 0, abi.encodePacked(firstDataBytes))]: 38105 +(test/StoreCore.t.sol) | get static field (1 slot) [bytes memory loadedData = StoreCore.getField(table, key, 0)]: 4592 +(test/StoreCore.t.sol) | set static field (overlap 2 slot) [StoreCore.setField(table, key, 1, abi.encodePacked(secondDataBytes))]: 33895 +(test/StoreCore.t.sol) | get static field (overlap 2 slot) [loadedData = StoreCore.getField(table, key, 1)]: 6375 +(test/StoreCore.t.sol) | set dynamic field (1 slot, first dynamic field) [StoreCore.setField(table, key, 2, thirdDataBytes)]: 57377 +(test/StoreCore.t.sol) | get dynamic field (1 slot, first dynamic field) [loadedData = StoreCore.getField(table, key, 2)]: 5357 +(test/StoreCore.t.sol) | set dynamic field (1 slot, second dynamic field) [StoreCore.setField(table, key, 3, fourthDataBytes)]: 35511 +(test/StoreCore.t.sol) | get dynamic field (1 slot, second dynamic field) [loadedData = StoreCore.getField(table, key, 3)]: 5372 +(test/StoreCore.t.sol) | set static record (1 slot) [StoreCore.setRecord(table, key, data)]: 34136 +(test/StoreCore.t.sol) | get static record (1 slot) [bytes memory loadedData = StoreCore.getRecord(table, key, schema)]: 4102 +(test/StoreCore.t.sol) | set static record (2 slots) [StoreCore.setRecord(table, key, data)]: 56691 +(test/StoreCore.t.sol) | get static record (2 slots) [bytes memory loadedData = StoreCore.getRecord(table, key, schema)]: 4991 +(test/StoreSwitch.t.sol) | check if delegatecall [isDelegate = StoreSwitch.isDelegateCall()]: 671 +(test/StoreSwitch.t.sol) | check if delegatecall [isDelegate = StoreSwitch.isDelegateCall()]: 627 +(test/System.t.sol) | extract msg.sender from calldata [address sender = _msgSender()]: 24 +(test/Vector2Table.t.sol) | register Vector2Table schema [Vector2Table.registerSchema()]: 28673 +(test/Vector2Table.t.sol) | set Vector2Table record [Vector2Table.set({ key: key, x: 1, y: 2 })]: 35206 +(test/Vector2Table.t.sol) | get Vector2Table record [Vector2 memory vector = Vector2Table.get(key)]: 6440 +(test/World.t.sol) | call autonomous system via World contract [WorldWithWorldTestSystem(address(world)).WorldTestSystem_move(entity, 1, 2)]: 45511 +(test/World.t.sol) | call delegate system via World contract [WorldWithWorldTestSystem(address(world)).WorldTestSystem_move(entity, 1, 2)]: 43376 \ No newline at end of file diff --git a/packages/store/git-install.sh b/packages/store/git-install.sh new file mode 100755 index 0000000000..b86de4f8c9 --- /dev/null +++ b/packages/store/git-install.sh @@ -0,0 +1,5 @@ +#! usr/bin/bash +giturl=https://github.com/$1.git +head=$(git ls-remote $giturl HEAD | head -n1 | awk '{print $1;}') +yarn add $giturl#$head +echo "Installed $giturl#$head" \ No newline at end of file diff --git a/packages/store/hardhat.config.ts b/packages/store/hardhat.config.ts new file mode 100644 index 0000000000..da00b249c6 --- /dev/null +++ b/packages/store/hardhat.config.ts @@ -0,0 +1,23 @@ +import { HardhatUserConfig } from "hardhat/config"; +import "./tasks/compile"; +import "solidity-docgen"; + +const config: HardhatUserConfig = { + paths: { + sources: "./src", + }, + solidity: { + version: "0.8.13", + settings: { + optimizer: { + enabled: true, + runs: 200, + }, + }, + }, + docgen: { + outputDir: "API", + }, +}; + +export default config; diff --git a/packages/store/index.ts b/packages/store/index.ts new file mode 100644 index 0000000000..cb0ff5c3b5 --- /dev/null +++ b/packages/store/index.ts @@ -0,0 +1 @@ +export {}; diff --git a/packages/store/index.yml b/packages/store/index.yml new file mode 100644 index 0000000000..67be39bdfd --- /dev/null +++ b/packages/store/index.yml @@ -0,0 +1,2 @@ +label: store +order: 50 diff --git a/packages/store/package.json b/packages/store/package.json new file mode 100644 index 0000000000..53fa3d3b26 --- /dev/null +++ b/packages/store/package.json @@ -0,0 +1,48 @@ +{ + "name": "@latticexyz/store", + "license": "MIT", + "version": "1.33.1", + "description": "Store", + "types": "./types/ethers-contracts/", + "repository": { + "type": "git", + "url": "https://github.com/latticexyz/mud.git", + "directory": "packages/store" + }, + "scripts": { + "prepare": "yarn build && chmod u+x git-install.sh", + "git:install": "bash git-install.sh", + "test": "forge test", + "build": "rimraf out && forge build --out out && yarn dist && yarn types", + "dist": "rimraf abi && mkdir abi && cp -rf out/*.sol/*.json abi/ && yarn rimraf abi/*.metadata.json", + "types": "rimraf types && typechain --target=ethers-v5 abi/*.json", + "prettier": "prettier --write 'src/**/*.sol'", + "solhint": "solhint --config ./.solhint.json 'src/**/*.sol'", + "lint": "yarn prettier && yarn solhint", + "link": "yarn link", + "docs": "rimraf API && hardhat docgen && echo 'label: API\norder: 50' > API/index.yml", + "release": "npm publish || echo 'version already published'", + "gasreport": " ../cli/dist/index.js gas-report --path test/** --save gas-report.txt" + }, + "devDependencies": { + "@typechain/ethers-v5": "^9.0.0", + "@types/mocha": "^9.1.1", + "ds-test": "https://github.com/dapphub/ds-test.git#c9ce3f25bde29fc5eb9901842bf02850dfd2d084", + "forge-std": "https://github.com/foundry-rs/forge-std.git#f36dab24d63d1c1945a05ed375ce341d3c1a49ed", + "hardhat": "^2.10.1", + "prettier": "^2.6.2", + "prettier-plugin-solidity": "^1.0.0-beta.19", + "rimraf": "^3.0.2", + "solhint": "^3.3.7", + "solidity-docgen": "^0.6.0-beta.22", + "ts-node": "10.7", + "typechain": "^8.1.1", + "typedoc": "^0.23.10", + "@latticexyz/cli": "^1.34.0" + }, + "peerDependencies": { + "ds-test": "https://github.com/dapphub/ds-test.git#c9ce3f25bde29fc5eb9901842bf02850dfd2d084", + "forge-std": "https://github.com/foundry-rs/forge-std.git#f36dab24d63d1c1945a05ed375ce341d3c1a49ed" + }, + "gitHead": "218f56893d268b0c5157a3e4c603b859e287a343" +} diff --git a/packages/store/remappings.txt b/packages/store/remappings.txt new file mode 100644 index 0000000000..aeeced7eb6 --- /dev/null +++ b/packages/store/remappings.txt @@ -0,0 +1,2 @@ +ds-test/=../../node_modules/ds-test/src/ +forge-std/=../../node_modules/forge-std/src/ diff --git a/packages/store/src/Buffer.sol b/packages/store/src/Buffer.sol new file mode 100644 index 0000000000..f4f610aa15 --- /dev/null +++ b/packages/store/src/Buffer.sol @@ -0,0 +1,368 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +// Acknowledgements: +// Based on @dk1a's Slice.sol library (https://github.com/dk1a/solidity-stringutils/blob/main/src/Slice.sol) +// Inspired by @ethier's DynamicBuffer.sol library (https://github.com/divergencetech/ethier/blob/main/contracts/utils/DynamicBuffer.sol) + +// Optimized for allocating a fixed size buffer and writing to it / reading from it. + +// First 16 bytes are the pointer to the data, followed by 16 bytes of data length. +type Buffer is uint256; + +using Buffer_ for Buffer global; + +library Buffer_ { + uint256 constant MASK_CAPACITY = uint256(type(uint128).max); + uint256 constant MASK_PTR = uint256(type(uint128).max) << 128; + + error Buffer_Overflow(uint256 capacity, uint256 requestedLength); + + /************************************************************************ + * + * STATIC FUNCTIONS + * + ************************************************************************/ + + /** + * @dev Allocates a new buffer with the given capacity. + */ + function allocate(uint128 _capacity) internal pure returns (Buffer) { + uint256 _ptr; + assembly { + let buf := mload(0x40) // free memory pointer + mstore(0x40, add(buf, add(32, _capacity))) // 32 bytes for the buffer header, plus the length of the buffer + mstore(buf, 0) // initialize length to 0 (memory is not cleared by default) + _ptr := add(buf, 32) // ptr to first data byte + } + + // Pointer is stored in upper 128 bits, capacity is stored in lower 128 bits + return Buffer.wrap(((_ptr << 128) | _capacity)); + } + + /** + * @dev Converts a bytes array to a buffer (without copying data) + */ + function fromBytes(bytes memory data) internal pure returns (Buffer) { + uint256 _ptr; + assembly { + _ptr := add(data, 32) // ptr to first data byte + } + + // Pointer is stored in upper 128 bits, length is stored in lower 128 bits + return Buffer.wrap((_ptr << 128) | uint128(data.length)); + } + + // TODO: add more overloads + function concat( + bytes memory data1, + bytes memory data2, + bytes memory data3 + ) internal pure returns (Buffer) { + Buffer buffer = allocate(uint128(data1.length + data2.length + data3.length)); + buffer.append(data1); + buffer.append(data2); + buffer.append(data3); + return buffer; + } + + function concat( + bytes memory data1, + bytes memory data2, + bytes memory data3, + bytes memory data4 + ) internal pure returns (Buffer) { + Buffer buffer = allocate(uint128(data1.length + data2.length + data3.length + data4.length)); + buffer.append(data1); + buffer.append(data2); + buffer.append(data3); + buffer.append(data4); + return buffer; + } + + /************************************************************************ + * + * INSTANCE FUNCTIONS + * + ************************************************************************/ + + /** + * @dev Returns the pointer to the start of an in-memory buffer. + */ + function ptr(Buffer self) internal pure returns (uint256) { + return Buffer.unwrap(self) >> 128; + } + + /** + * @dev Returns the current length in bytes. + */ + function length(Buffer self) internal pure returns (uint128 _length) { + uint256 _ptr = ptr(self); + assembly { + _length := mload(sub(_ptr, 32)) + } + } + + /** + * @dev Returns the capacity in bytes. + */ + function capacity(Buffer self) internal pure returns (uint128 _capacity) { + return uint128(Buffer.unwrap(self)); + } + + /** + * @dev Read a 32 bytes from the buffer starting at the given offset (without checking for overflows) + */ + function read32(Buffer self, uint256 offset) internal pure returns (bytes32 value) { + uint256 _ptr = ptr(self); + assembly { + value := mload(add(_ptr, offset)) + } + } + + /** + * @dev Read a 8 bytes from the buffer starting at the given offset (without checking for overflows) + */ + function read8(Buffer self, uint256 offset) internal pure returns (bytes8 value) { + return bytes8(read32(self, offset)); + } + + /** + * @dev Read a 1 byte from the buffer starting at the given offset + */ + function read1(Buffer self, uint256 offset) internal pure returns (bytes1 value) { + return bytes1(read32(self, offset)); + } + + // TODO: add more typed utils to read from the buffer + + /** + * @dev Appends the given bytes to the buffer (checking for overflows) + */ + function append(Buffer self, bytes memory data) internal pure { + uint128 _newLength = length(self) + uint128(data.length); + checkCapacity(self, _newLength); + appendUnchecked(self, data); + } + + /** + * @dev Appends bytes32 to the buffer (checking for overflows) + */ + function append(Buffer self, bytes32 data) internal pure { + append(self, data, 32); + } + + /** + * @dev Appends _dataLength of the given bytes32 to the buffer (checking for overflows) + */ + function append( + Buffer self, + bytes32 data, + uint128 _dataLength + ) internal pure { + uint128 _newLength = length(self) + _dataLength; + checkCapacity(self, _newLength); + appendUnchecked(self, data, _dataLength); + } + + /** + * @dev Appends _dataLength of the given bytes32 to the buffer (without checking for overflows) + */ + function appendUnchecked( + Buffer self, + bytes32 data, + uint128 _dataLength + ) internal pure { + uint256 _ptr = ptr(self); + uint128 _length = length(self); + + // Update the current buffer length + _setLengthUnchecked(self, _length + _dataLength); + + // Copy over given data to the buffer + assembly { + mstore(add(_ptr, _length), data) + } + } + + /** + * @dev Appends the given bytes to the buffer (without checking for overflows) + */ + function appendUnchecked(Buffer self, bytes memory data) internal pure { + uint256 _ptr = ptr(self); + uint128 _dataLength = uint128(data.length); + uint128 _length = length(self); + uint128 _newLength = _length + uint128(data.length); + + // Update the current buffer length + _setLengthUnchecked(self, _newLength); + + // Copy over given data to the buffer + assembly { + for { + let i := 0 + } lt(i, _dataLength) { + i := add(i, 32) + } { + mstore(add(add(_ptr, _length), i), mload(add(data, add(32, i)))) + } + } + } + + /** + * @dev returns the buffer as a bytes array (without copying the data) + */ + function toBytes(Buffer self) internal pure returns (bytes memory _bytes) { + uint256 _ptr = ptr(self); + assembly { + _bytes := sub(_ptr, 32) + } + } + + function slice( + Buffer self, + uint256 _start, + uint256 _length + ) internal pure returns (bytes memory) { + return sliceBytes(toBytes(self), _start, _length); + } + + /** + * @dev copies a slice of the buffer to a new memory location and returns it as a bytes array (without checking for overflows) + */ + + /** + * @dev copies the buffer contents to a new memory location and lays it out like a right aligned (eg uint) memory array with the given size per element (in bytes) + * @return arrayPtr the pointer to the start of the array, needs to be casted to the expected type using assembly + */ + function toArray(Buffer self, uint256 elementSize) internal pure returns (uint256 arrayPtr) { + return toArray(self, elementSize, false); + } + + /** + * @dev copies the buffer contents to a new memory location and lays it out like a memory array with the given size per element (in bytes) + * @return arrayPtr the pointer to the start of the array, needs to be casted to the expected type using assembly + */ + function toArray( + Buffer self, + uint256 elementSize, + bool leftAligned + ) internal pure returns (uint256 arrayPtr) { + uint256 _ptr = ptr(self); + uint128 _length = length(self); + uint256 padLeft = leftAligned ? 0 : 256 - elementSize * 8; + + assembly { + arrayPtr := mload(0x40) // free memory pointer + let arrayLen := div(_length, elementSize) // array length + mstore(0x40, add(arrayPtr, add(mul(arrayLen, 32), 32))) // update free memory pointer (array length + array data) + mstore(arrayPtr, arrayLen) // store array length + + for { + let i := 0 + let arrayCursor := add(arrayPtr, 32) // skip array length + let dataCursor := _ptr + } lt(i, arrayLen) { + // loop until we reach the end of the buffer + i := add(i, 1) + dataCursor := add(dataCursor, elementSize) // increment buffer pointer by one element size + arrayCursor := add(arrayCursor, 32) // increment array pointer by one slot + } { + mstore(arrayCursor, shr(padLeft, mload(dataCursor))) // copy one element from buffer to array + } + } + } + + /** + * @dev Modify buffer length (checking capacity) + */ + function _setLength(Buffer self, uint128 _length) internal pure { + checkCapacity(self, _length); + _setLengthUnchecked(self, _length); + } + + /** + * @dev Modify buffer length (without checking capacity) + */ + function _setLengthUnchecked(Buffer self, uint128 _length) internal pure { + uint256 _ptr = ptr(self); + assembly { + mstore(sub(_ptr, 32), _length) + } + } + + /** + * @dev Check if the buffer has enough capacity to store a given length. + */ + function checkCapacity(Buffer self, uint128 _length) internal pure { + if (capacity(self) < _length) { + revert Buffer_Overflow(capacity(self), _length); + } + } +} + +// From https://github.com/GNSPS/solidity-bytes-utils/blob/master/contracts/BytesLib.sol +function sliceBytes( + bytes memory _bytes, + uint256 _start, + uint256 _length +) pure returns (bytes memory) { + require(_length + 31 >= _length, "slice_overflow"); + require(_bytes.length >= _start + _length, "slice_outOfBounds"); + + bytes memory tempBytes; + + assembly { + switch iszero(_length) + case 0 { + // Get a location of some free memory and store it in tempBytes as + // Solidity does for memory variables. + tempBytes := mload(0x40) + + // The first word of the slice result is potentially a partial + // word read from the original array. To read it, we calculate + // the length of that partial word and start copying that many + // bytes into the array. The first word we copy will start with + // data we don't care about, but the last `lengthmod` bytes will + // land at the beginning of the contents of the new array. When + // we're done copying, we overwrite the full first word with + // the actual length of the slice. + let lengthmod := and(_length, 31) + + // The multiplication in the next line is necessary + // because when slicing multiples of 32 bytes (lengthmod == 0) + // the following copy loop was copying the origin's length + // and then ending prematurely not copying everything it should. + let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) + let end := add(mc, _length) + + for { + // The multiplication in the next line has the same exact purpose + // as the one above. + let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) + } lt(mc, end) { + mc := add(mc, 0x20) + cc := add(cc, 0x20) + } { + mstore(mc, mload(cc)) + } + + mstore(tempBytes, _length) + + //update free-memory pointer + //allocating the array padded to 32 bytes like the compiler does now + mstore(0x40, and(add(mc, 31), not(31))) + } + //if we want a zero-length slice let's just return a zero-length array + default { + tempBytes := mload(0x40) + //zero out the 32 bytes slice we are about to return + //we need to do it because Solidity does not garbage collect + mstore(tempBytes, 0) + + mstore(0x40, add(tempBytes, 0x20)) + } + } + + return tempBytes; +} diff --git a/packages/store/src/Bytes.sol b/packages/store/src/Bytes.sol new file mode 100644 index 0000000000..a4a4b4c7e9 --- /dev/null +++ b/packages/store/src/Bytes.sol @@ -0,0 +1,659 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import { console } from "forge-std/console.sol"; +import { Utils } from "./Utils.sol"; +import { SchemaType } from "./Types.sol"; +import { console } from "forge-std/console.sol"; +import { Buffer, Buffer_ } from "./Buffer.sol"; +import { Cast } from "./Cast.sol"; + +library Bytes { + error Bytes_InputTooShort(); + + /************************************************************************ + * + * ANYTHING -> BYTES + * + ************************************************************************/ + + /** + * Converts a `bytes` memory array to a single `bytes` memory value. + * TODO: optimize gas cost + */ + function from(bytes[] memory input) internal pure returns (bytes memory output) { + output = new bytes(0); + for (uint256 i; i < input.length; i++) { + output = bytes.concat(output, input[i]); + } + } + + function from(uint8[] memory input) internal pure returns (bytes memory output) { + bytes32 ptr; + assembly { + ptr := input + } + + return _from(ptr, 1); + } + + function from(SchemaType[] memory input) internal pure returns (bytes memory output) { + bytes32 ptr; + assembly { + ptr := input + } + + return _from(ptr, 1); + } + + function from(uint16[] memory input) internal pure returns (bytes memory output) { + bytes32 ptr; + assembly { + ptr := input + } + + return _from(ptr, 2); + } + + function from(uint32[] memory input) internal pure returns (bytes memory output) { + bytes32 ptr; + assembly { + ptr := input + } + + return _from(ptr, 4); + } + + function from(bytes24[] memory input) internal pure returns (bytes memory output) { + bytes32 ptr; + assembly { + ptr := input + } + + return _from(ptr, 24, true); + } + + function from(address[] memory input) internal pure returns (bytes memory output) { + bytes32 ptr; + assembly { + ptr := input + } + + return _from(ptr, 20); + } + + function _from(bytes32 _ptr, uint256 _bytesPerElement) internal pure returns (bytes memory output) { + return _from(_ptr, _bytesPerElement, false); + } + + function _from( + bytes32 _ptr, + uint256 _bytesPerElement, + bool leftAligned + ) internal pure returns (bytes memory output) { + uint256 shiftBits = leftAligned ? 0 : (32 - _bytesPerElement) * 8; + + assembly { + let inputLength := mload(_ptr) + let outputBytes := mul(inputLength, _bytesPerElement) + + // Allocate memory for the output and store its length + output := mload(0x40) + mstore(output, outputBytes) + + // Update the free memory pointer + mstore(0x40, add(output, add(32, outputBytes))) + + let outputPtr := add(output, 32) + for { + let inputPtr := add(_ptr, 32) // Start at first element + // Stop at last element + } lt(inputPtr, add(add(_ptr, 32), mul(mload(_ptr), 32))) { + inputPtr := add(inputPtr, 32) // Go to next input element + outputPtr := add(outputPtr, _bytesPerElement) // Go to next output slot + } { + mstore(outputPtr, shl(shiftBits, mload(inputPtr))) // Store the value in minimal bytes + } + } + } + + /************************************************************************ + * + * BYTES -> ANYTHING + * + ************************************************************************/ + + /** + * Converts a `bytes` memory blob to a single `bytes32` memory value, starting at the given byte offset. + */ + function toBytes32(bytes memory input, uint256 offset) internal pure returns (bytes32 output) { + assembly { + // input is a pointer to the start of the bytes array + // in memory, the first 32 bytes are the length of the array + // so we add 32 to the pointer to get to the start of the data + // then we add the start offset to get to the start of the desired word + output := mload(add(input, add(0x20, offset))) + } + } + + function toBytes32(bytes memory input) internal pure returns (bytes32 output) { + return bytes32(input); + } + + function toUint256(bytes memory input) internal pure returns (uint256 output) { + return uint256(bytes32(input)); + } + + function toUint32(bytes memory input) internal pure returns (uint32 output) { + return uint32(bytes4(input)); + } + + function toAddress(bytes memory input) internal pure returns (address output) { + return address(bytes20(input)); + } + + function toBytes4(bytes memory input) internal pure returns (bytes4 output) { + return bytes4(input); + } + + function toUint8(bytes memory input) internal pure returns (uint8 output) { + return uint8(input[0]); + } + + /** + * Converts a `bytes` memory blob to a `bytes32` memory array. + */ + function toBytes32Array(bytes memory input) internal pure returns (bytes32[] memory output) { + output = new bytes32[](Utils.divCeil(input.length, 32)); + for (uint256 i = 0; i < output.length; i++) { + output[i] = toBytes32(input, i * 32); + } + return output; + } + + /** + * Converts a `bytes` memory blob to a `SchemaType` memory array. + */ + function toSchemaTypeArray(bytes memory input) internal pure returns (SchemaType[] memory output) { + output = new SchemaType[](input.length); + for (uint256 i = 0; i < output.length; i++) { + output[i] = SchemaType(uint8(input[i])); + } + return output; + } + + /** + * Converts a tightly packed uint32 array into a regular uint32 array. + */ + function toUint32Array(bytes memory input) internal pure returns (uint32[] memory output) { + return Cast.toUint32Array(Buffer_.fromBytes(input).toArray(4)); + } + + /** + * Converts a tightly packed address array into a regular address array. + */ + function toAddressArray(bytes memory input) internal pure returns (address[] memory output) { + return Cast.toAddressArray(Buffer_.fromBytes(input).toArray(20)); + } + + /** + * Converts a tightly packed bytes24 array into a regular bytes24 array. + */ + function toBytes24Array(bytes memory input) internal pure returns (bytes24[] memory output) { + return Cast.toBytes24Array(Buffer_.fromBytes(input).toArray(24, true)); + } + + /************************************************************************ + * + * UTILS + * + ************************************************************************/ + + function equals(bytes memory a, bytes memory b) internal pure returns (bool) { + if (a.length != b.length) { + return false; + } + return keccak256(a) == keccak256(b); + } + + /************************************************************************ + * + * SET + * + ************************************************************************/ + + /** + * Overwrite a single byte of a `bytes32` value and return the new value. + */ + function setBytes1( + bytes32 input, + uint256 index, + bytes1 overwrite + ) internal pure returns (bytes32 output) { + bytes1 mask = 0xff; + assembly { + mask := shr(mul(8, index), mask) // create a mask by shifting 0xff right by index bytes + output := and(input, not(mask)) // zero out the byte at index + output := or(output, shr(mul(8, index), overwrite)) // set the byte at index + } + return output; + } + + /** + * Overwrite two bytes of a `bytes32` value and return the new value. + */ + function setBytes2( + bytes32 input, + uint256 index, + bytes2 overwrite + ) internal pure returns (bytes32 output) { + bytes2 mask = 0xffff; + assembly { + mask := shr(mul(8, index), mask) // create a mask by shifting 0xffff right by index bytes + output := and(input, not(mask)) // zero out the byte at index + output := or(output, shr(mul(8, index), overwrite)) // set the byte at index + } + return output; + } + + /** + * Overwrite four bytes of a `bytes32` value and return the new value. + */ + function setBytes4( + bytes32 input, + uint256 index, + bytes4 overwrite + ) internal pure returns (bytes32 output) { + bytes4 mask = 0xffffffff; + assembly { + mask := shr(mul(8, index), mask) // create a mask by shifting 0xffffffff right by index bytes + output := and(input, not(mask)) // zero out the byte at index + output := or(output, shr(mul(8, index), overwrite)) // set the byte at index + } + return output; + } + + /************************************************************************ + * + * SLICE + * + ************************************************************************/ + + // From https://github.com/GNSPS/solidity-bytes-utils/blob/master/contracts/BytesLib.sol + function slice( + bytes memory _bytes, + uint256 _start, + uint256 _length + ) internal pure returns (bytes memory) { + require(_length + 31 >= _length, "slice_overflow"); + require(_bytes.length >= _start + _length, "slice_outOfBounds"); + + bytes memory tempBytes; + + assembly { + switch iszero(_length) + case 0 { + // Get a location of some free memory and store it in tempBytes as + // Solidity does for memory variables. + tempBytes := mload(0x40) + + // The first word of the slice result is potentially a partial + // word read from the original array. To read it, we calculate + // the length of that partial word and start copying that many + // bytes into the array. The first word we copy will start with + // data we don't care about, but the last `lengthmod` bytes will + // land at the beginning of the contents of the new array. When + // we're done copying, we overwrite the full first word with + // the actual length of the slice. + let lengthmod := and(_length, 31) + + // The multiplication in the next line is necessary + // because when slicing multiples of 32 bytes (lengthmod == 0) + // the following copy loop was copying the origin's length + // and then ending prematurely not copying everything it should. + let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) + let end := add(mc, _length) + + for { + // The multiplication in the next line has the same exact purpose + // as the one above. + let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) + } lt(mc, end) { + mc := add(mc, 0x20) + cc := add(cc, 0x20) + } { + mstore(mc, mload(cc)) + } + + mstore(tempBytes, _length) + + //update free-memory pointer + //allocating the array padded to 32 bytes like the compiler does now + mstore(0x40, and(add(mc, 31), not(31))) + } + //if we want a zero-length slice let's just return a zero-length array + default { + tempBytes := mload(0x40) + //zero out the 32 bytes slice we are about to return + //we need to do it because Solidity does not garbage collect + mstore(tempBytes, 0) + + mstore(0x40, add(tempBytes, 0x20)) + } + } + + return tempBytes; + } + + /** Slice bytes to bytes1 without copying data */ + function slice1(bytes memory data, uint256 start) internal pure returns (bytes1) { + bytes1 output; + assembly { + output := mload(add(add(data, 0x20), start)) + } + return output; + } + + function slice1(bytes32 data, uint256 start) internal pure returns (bytes1) { + bytes1 output; + assembly { + output := shl(mul(8, start), data) + } + return output; + } + + /** Slice bytes to bytes2 without copying data */ + function slice2(bytes memory data, uint256 start) internal pure returns (bytes2) { + bytes2 output; + assembly { + output := mload(add(add(data, 0x20), start)) + } + return output; + } + + function slice2(bytes32 data, uint256 start) internal pure returns (bytes2) { + bytes2 output; + assembly { + output := shl(mul(8, start), data) + } + return output; + } + + /** Slice bytes to bytes3 without copying data */ + function slice3(bytes memory data, uint256 start) internal pure returns (bytes3) { + bytes3 output; + assembly { + output := mload(add(add(data, 0x20), start)) + } + return output; + } + + /** Slice bytes to bytes4 without copying data */ + function slice4(bytes memory data, uint256 start) internal pure returns (bytes4) { + bytes4 output; + assembly { + output := mload(add(add(data, 0x20), start)) + } + return output; + } + + function slice4(bytes32 data, uint256 start) internal pure returns (bytes4) { + bytes2 output; + assembly { + output := shl(mul(8, start), data) + } + return output; + } + + /** Slice bytes to bytes5 without copying data */ + function slice5(bytes memory data, uint256 start) internal pure returns (bytes5) { + bytes5 output; + assembly { + output := mload(add(add(data, 0x20), start)) + } + return output; + } + + /** Slice bytes to bytes6 without copying data */ + function slice6(bytes memory data, uint256 start) internal pure returns (bytes6) { + bytes6 output; + assembly { + output := mload(add(add(data, 0x20), start)) + } + return output; + } + + /** Slice bytes to bytes7 without copying data */ + function slice7(bytes memory data, uint256 start) internal pure returns (bytes7) { + bytes7 output; + assembly { + output := mload(add(add(data, 0x20), start)) + } + return output; + } + + /** Slice bytes to bytes8 without copying data */ + function slice8(bytes memory data, uint256 start) internal pure returns (bytes8) { + bytes8 output; + assembly { + output := mload(add(add(data, 0x20), start)) + } + return output; + } + + /** Slice bytes to bytes9 without copying data */ + function slice9(bytes memory data, uint256 start) internal pure returns (bytes9) { + bytes9 output; + assembly { + output := mload(add(add(data, 0x20), start)) + } + return output; + } + + /** Slice bytes to bytes10 without copying data */ + function slice10(bytes memory data, uint256 start) internal pure returns (bytes10) { + bytes10 output; + assembly { + output := mload(add(add(data, 0x20), start)) + } + return output; + } + + /** Slice bytes to bytes11 without copying data */ + function slice11(bytes memory data, uint256 start) internal pure returns (bytes11) { + bytes11 output; + assembly { + output := mload(add(add(data, 0x20), start)) + } + return output; + } + + /** Slice bytes to bytes12 without copying data */ + function slice12(bytes memory data, uint256 start) internal pure returns (bytes12) { + bytes12 output; + assembly { + output := mload(add(add(data, 0x20), start)) + } + return output; + } + + /** Slice bytes to bytes13 without copying data */ + function slice13(bytes memory data, uint256 start) internal pure returns (bytes13) { + bytes13 output; + assembly { + output := mload(add(add(data, 0x20), start)) + } + return output; + } + + /** Slice bytes to bytes14 without copying data */ + function slice14(bytes memory data, uint256 start) internal pure returns (bytes14) { + bytes14 output; + assembly { + output := mload(add(add(data, 0x20), start)) + } + return output; + } + + /** Slice bytes to bytes15 without copying data */ + function slice15(bytes memory data, uint256 start) internal pure returns (bytes15) { + bytes15 output; + assembly { + output := mload(add(add(data, 0x20), start)) + } + return output; + } + + /** Slice bytes to bytes16 without copying data */ + function slice16(bytes memory data, uint256 start) internal pure returns (bytes16) { + bytes16 output; + assembly { + output := mload(add(add(data, 0x20), start)) + } + return output; + } + + /** Slice bytes to bytes17 without copying data */ + function slice17(bytes memory data, uint256 start) internal pure returns (bytes17) { + bytes17 output; + assembly { + output := mload(add(add(data, 0x20), start)) + } + return output; + } + + /** Slice bytes to bytes18 without copying data */ + function slice18(bytes memory data, uint256 start) internal pure returns (bytes18) { + bytes18 output; + assembly { + output := mload(add(add(data, 0x20), start)) + } + return output; + } + + /** Slice bytes to bytes19 without copying data */ + function slice19(bytes memory data, uint256 start) internal pure returns (bytes19) { + bytes19 output; + assembly { + output := mload(add(add(data, 0x20), start)) + } + return output; + } + + /** Slice bytes to bytes20 without copying data */ + function slice20(bytes memory data, uint256 start) internal pure returns (bytes20) { + bytes20 output; + assembly { + output := mload(add(add(data, 0x20), start)) + } + return output; + } + + /** Slice bytes to bytes21 without copying data */ + function slice21(bytes memory data, uint256 start) internal pure returns (bytes21) { + bytes21 output; + assembly { + output := mload(add(add(data, 0x20), start)) + } + return output; + } + + /** Slice bytes to bytes22 without copying data */ + function slice22(bytes memory data, uint256 start) internal pure returns (bytes22) { + bytes22 output; + assembly { + output := mload(add(add(data, 0x20), start)) + } + return output; + } + + /** Slice bytes to bytes23 without copying data */ + function slice23(bytes memory data, uint256 start) internal pure returns (bytes23) { + bytes23 output; + assembly { + output := mload(add(add(data, 0x20), start)) + } + return output; + } + + /** Slice bytes to bytes24 without copying data */ + function slice24(bytes memory data, uint256 start) internal pure returns (bytes24) { + bytes24 output; + assembly { + output := mload(add(add(data, 0x20), start)) + } + return output; + } + + /** Slice bytes to bytes25 without copying data */ + function slice25(bytes memory data, uint256 start) internal pure returns (bytes25) { + bytes25 output; + assembly { + output := mload(add(add(data, 0x20), start)) + } + return output; + } + + /** Slice bytes to bytes26 without copying data */ + function slice26(bytes memory data, uint256 start) internal pure returns (bytes26) { + bytes26 output; + assembly { + output := mload(add(add(data, 0x20), start)) + } + return output; + } + + /** Slice bytes to bytes27 without copying data */ + function slice27(bytes memory data, uint256 start) internal pure returns (bytes27) { + bytes27 output; + assembly { + output := mload(add(add(data, 0x20), start)) + } + return output; + } + + /** Slice bytes to bytes28 without copying data */ + function slice28(bytes memory data, uint256 start) internal pure returns (bytes28) { + bytes28 output; + assembly { + output := mload(add(add(data, 0x20), start)) + } + return output; + } + + /** Slice bytes to bytes29 without copying data */ + function slice29(bytes memory data, uint256 start) internal pure returns (bytes29) { + bytes29 output; + assembly { + output := mload(add(add(data, 0x20), start)) + } + return output; + } + + /** Slice bytes to bytes30 without copying data */ + function slice30(bytes memory data, uint256 start) internal pure returns (bytes30) { + bytes30 output; + assembly { + output := mload(add(add(data, 0x20), start)) + } + return output; + } + + /** Slice bytes to bytes31 without copying data */ + function slice31(bytes memory data, uint256 start) internal pure returns (bytes31) { + bytes31 output; + assembly { + output := mload(add(add(data, 0x20), start)) + } + return output; + } + + /** Slice bytes to bytes32 without copying data */ + function slice32(bytes memory data, uint256 start) internal pure returns (bytes32) { + bytes32 output; + assembly { + output := mload(add(add(data, 0x20), start)) + } + return output; + } +} diff --git a/packages/store/src/Cast.sol b/packages/store/src/Cast.sol new file mode 100644 index 0000000000..3e8d1aa1c0 --- /dev/null +++ b/packages/store/src/Cast.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +library Cast { + function toUint32Array(uint256 ptr) internal pure returns (uint32[] memory arr) { + assembly { + arr := ptr + } + } + + function toUint256Array(uint256 ptr) internal pure returns (uint256[] memory arr) { + assembly { + arr := ptr + } + } + + function toBytes24Array(uint256 ptr) internal pure returns (bytes24[] memory arr) { + assembly { + arr := ptr + } + } + + function toAddressArray(uint256 ptr) internal pure returns (address[] memory arr) { + assembly { + arr := ptr + } + } +} diff --git a/packages/store/src/IStore.sol b/packages/store/src/IStore.sol new file mode 100644 index 0000000000..03873cc80d --- /dev/null +++ b/packages/store/src/IStore.sol @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import { SchemaType } from "./Types.sol"; +import { Schema } from "./Schema.sol"; + +interface IStore { + event MudStoreSetRecord(bytes32 table, bytes32[] key, bytes data); + event MudStoreSetField(bytes32 table, bytes32[] key, uint8 schemaIndex, bytes data); + event MudStoreDeleteRecord(bytes32 table, bytes32[] key); + + function registerSchema(bytes32 table, Schema schema) external; + + function getSchema(bytes32 table) external view returns (Schema schema); + + // Set full record (including full dynamic data) + function setRecord( + bytes32 table, + bytes32[] memory key, + bytes memory data + ) external; + + // Set partial data at schema index + function setField( + bytes32 table, + bytes32[] memory key, + uint8 schemaIndex, + bytes memory data + ) external; + + // Register hooks to be called when a record or field is set or deleted + function registerHook(bytes32 table, IStoreHook hooks) external; + + // Set full record (including full dynamic data) + function deleteRecord(bytes32 table, bytes32[] memory key) external; + + // Get full record (including full array, load table schema from storage) + function getRecord(bytes32 table, bytes32[] memory key) external view returns (bytes memory data); + + // Get full record (including full array) + function getRecord( + bytes32 table, + bytes32[] memory key, + Schema schema + ) external view returns (bytes memory data); + + // Get partial data at schema index + function getField( + bytes32 table, + bytes32[] memory key, + uint8 schemaIndex + ) external view returns (bytes memory data); + + // If this function exists on the contract, it is a store + // TODO: benchmark this vs. using a known storage slot to determine whether a contract is a Store + function isStore() external view; +} + +interface IStoreHook { + function onSetRecord( + bytes32 table, + bytes32[] memory key, + bytes memory data + ) external; + + function onSetField( + bytes32 table, + bytes32[] memory key, + uint8 schemaIndex, + bytes memory data + ) external; + + function onDeleteRecord(bytes32 table, bytes32[] memory key) external; +} diff --git a/packages/store/src/Memory.sol b/packages/store/src/Memory.sol new file mode 100644 index 0000000000..f8a4b8dcc8 --- /dev/null +++ b/packages/store/src/Memory.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import { Utils } from "./Utils.sol"; +import { Bytes } from "./Bytes.sol"; + +library Memory { + function load(uint256 memoryPointer) internal pure returns (bytes32 data) { + assembly { + data := mload(memoryPointer) + } + } + + function load(uint256 memoryPointer, uint256 offset) internal pure returns (bytes32 data) { + assembly { + data := mload(add(memoryPointer, offset)) + } + } + + function dataPointer(bytes memory data) internal pure returns (uint256 memoryPointer) { + assembly { + memoryPointer := add(data, 0x20) + } + } + + function lengthPointer(bytes memory data) internal pure returns (uint256 memoryPointer) { + assembly { + memoryPointer := data + } + } +} diff --git a/packages/store/src/PackedCounter.sol b/packages/store/src/PackedCounter.sol new file mode 100644 index 0000000000..94ac2abe4c --- /dev/null +++ b/packages/store/src/PackedCounter.sol @@ -0,0 +1,143 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import { SchemaType, getStaticByteLength } from "./Types.sol"; +import { Bytes } from "./Bytes.sol"; + +// - 4 bytes accumulated counter +// - 2 bytes length per counter +type PackedCounter is bytes32; + +using PackedCounterLib for PackedCounter global; + +library PackedCounterLib { + /************************************************************************ + * + * STATIC FUNCTIONS + * + ************************************************************************/ + + /** + * Encode the given counters into a single packed counter + * - 4 bytes for the accumulated length + * - 2 bytes per counter -> max 14 counters + */ + function pack(uint16[] memory counters) internal pure returns (PackedCounter) { + bytes32 packedCounter; + uint32 accumulator; + + // Compute the sum of all counters + // and pack the counters + for (uint256 i; i < counters.length; ) { + packedCounter = Bytes.setBytes2(packedCounter, 4 + 2 * i, bytes2(counters[i])); + accumulator += counters[i]; + unchecked { + i++; + } + } + + // Store total length + packedCounter = Bytes.setBytes4(packedCounter, 0, bytes4(accumulator)); + + return PackedCounter.wrap(packedCounter); + } + + // Overrides for pack function + function pack(uint16 a) internal pure returns (PackedCounter) { + uint16[] memory counters = new uint16[](1); + counters[0] = a; + return pack(counters); + } + + function pack(uint16 a, uint16 b) internal pure returns (PackedCounter) { + uint16[] memory counters = new uint16[](2); + counters[0] = a; + counters[1] = b; + return pack(counters); + } + + function pack( + uint16 a, + uint16 b, + uint16 c + ) internal pure returns (PackedCounter) { + uint16[] memory counters = new uint16[](3); + counters[0] = a; + counters[1] = b; + counters[2] = c; + return pack(counters); + } + + function pack( + uint16 a, + uint16 b, + uint16 c, + uint16 d + ) internal pure returns (PackedCounter) { + uint16[] memory counters = new uint16[](4); + counters[0] = a; + counters[1] = b; + counters[2] = c; + counters[3] = d; + return pack(counters); + } + + /************************************************************************ + * + * INSTANCE FUNCTIONS + * + ************************************************************************/ + + /** + * Decode the accumulated counter + * (first four bytes of packed counter) + */ + function total(PackedCounter packedCounter) internal pure returns (uint256) { + return uint256(uint32(bytes4(PackedCounter.unwrap(packedCounter)))); + } + + /** + * Decode the counter at the given index + * (two bytes per counter after the first four bytes) + */ + function atIndex(PackedCounter packedCounter, uint256 index) internal pure returns (uint256) { + uint256 offset = 4 + index * 2; + return uint256(uint16(Bytes.slice2(PackedCounter.unwrap(packedCounter), offset))); + } + + /** + * Set a counter at the given index, return the new packed counter + */ + function setAtIndex( + PackedCounter packedCounter, + uint256 index, + uint256 newValueAtIndex + ) internal pure returns (PackedCounter) { + bytes32 rawPackedCounter = PackedCounter.unwrap(packedCounter); + + // Get current lengths (total and at index) + uint256 accumulator = total(packedCounter); + uint256 currentValueAtIndex = atIndex(packedCounter, uint8(index)); + + // Compute the difference and update the total value + if (newValueAtIndex >= currentValueAtIndex) { + accumulator += newValueAtIndex - currentValueAtIndex; + } else { + accumulator -= currentValueAtIndex - newValueAtIndex; + } + + // Set the new accumulated value and value at index + uint256 offset = 4 + index * 2; // (4 bytes total length, 2 bytes per dynamic schema) + rawPackedCounter = Bytes.setBytes4(rawPackedCounter, 0, bytes4(uint32(accumulator))); + rawPackedCounter = Bytes.setBytes2(rawPackedCounter, offset, bytes2(uint16(newValueAtIndex))); + + return PackedCounter.wrap(rawPackedCounter); + } + + /* + * Unwrap the packed counter + */ + function unwrap(PackedCounter packedCounter) internal pure returns (bytes32) { + return PackedCounter.unwrap(packedCounter); + } +} diff --git a/packages/store/src/Schema.sol b/packages/store/src/Schema.sol new file mode 100644 index 0000000000..033cf5d023 --- /dev/null +++ b/packages/store/src/Schema.sol @@ -0,0 +1,227 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import { SchemaType, getStaticByteLength } from "./Types.sol"; +import { Bytes } from "./Bytes.sol"; + +// - 2 bytes static length of the schema +// - 1 byte for number of static size fields +// - 1 byte for number of dynamic size fields +// - 28 bytes for 28 schema types (max 14 dynamic fields to we can pack their lengths into 1 word) +type Schema is bytes32; + +using SchemaLib for Schema global; + +library SchemaLib { + error SchemaLib_InvalidLength(uint256 length); + error SchemaLib_StaticTypeAfterDynamicType(); + + /************************************************************************ + * + * STATIC FUNCTIONS + * + ************************************************************************/ + + /** + * Encode the given schema into a single bytes32 + */ + function encode(SchemaType[] memory _schema) internal pure returns (Schema) { + if (_schema.length > 28) revert SchemaLib_InvalidLength(_schema.length); + bytes32 schema; + uint16 length; + uint8 staticFields; + + // Compute the length of the schema and the number of static fields + // and store the schema types in the encoded schema + bool hasDynamicFields; + for (uint256 i = 0; i < _schema.length; ) { + uint16 staticByteLength = uint16(getStaticByteLength(_schema[i])); + + // Increase the static field count if the field is static + if (staticByteLength > 0) { + // Revert if we have seen a dynamic field before, but now we see a static field + if (hasDynamicFields) revert SchemaLib_StaticTypeAfterDynamicType(); + staticFields++; + } else { + // Flag that we have seen a dynamic field + hasDynamicFields = true; + } + + length += staticByteLength; + schema = Bytes.setBytes1(schema, i + 4, bytes1(uint8(_schema[i]))); + unchecked { + i++; + } + } + + // Require max 14 dynamic fields + uint8 dynamicFields = uint8(_schema.length) - staticFields; + if (dynamicFields > 14) revert SchemaLib_InvalidLength(dynamicFields); + + // Store total static length, and number of static and dynamic fields + schema = Bytes.setBytes2(schema, 0, (bytes2(length))); // 2 length bytes + schema = Bytes.setBytes1(schema, 2, bytes1(staticFields)); // number of static fields + schema = Bytes.setBytes1(schema, 3, bytes1(dynamicFields)); // number of dynamic fields + + return Schema.wrap(schema); + } + + // Overrides for encode functions + function encode(SchemaType a) internal pure returns (Schema) { + SchemaType[] memory schema = new SchemaType[](1); + schema[0] = a; + return encode(schema); + } + + function encode(SchemaType a, SchemaType b) internal pure returns (Schema) { + SchemaType[] memory schema = new SchemaType[](2); + schema[0] = a; + schema[1] = b; + return encode(schema); + } + + function encode( + SchemaType a, + SchemaType b, + SchemaType c + ) internal pure returns (Schema) { + SchemaType[] memory schema = new SchemaType[](3); + schema[0] = a; + schema[1] = b; + schema[2] = c; + return encode(schema); + } + + function encode( + SchemaType a, + SchemaType b, + SchemaType c, + SchemaType d + ) internal pure returns (Schema) { + SchemaType[] memory schema = new SchemaType[](4); + schema[0] = a; + schema[1] = b; + schema[2] = c; + schema[3] = d; + return encode(schema); + } + + function encode( + SchemaType a, + SchemaType b, + SchemaType c, + SchemaType d, + SchemaType e + ) internal pure returns (Schema) { + SchemaType[] memory schema = new SchemaType[](5); + schema[0] = a; + schema[1] = b; + schema[2] = c; + schema[3] = d; + schema[4] = e; + return encode(schema); + } + + function encode( + SchemaType a, + SchemaType b, + SchemaType c, + SchemaType d, + SchemaType e, + SchemaType f + ) internal pure returns (Schema) { + SchemaType[] memory schema = new SchemaType[](6); + schema[0] = a; + schema[1] = b; + schema[2] = c; + schema[3] = d; + schema[4] = e; + schema[5] = f; + return encode(schema); + } + + /************************************************************************ + * + * INSTANCE FUNCTIONS + * + ************************************************************************/ + + /** + * Get the length of the static data for the given schema + */ + function staticDataLength(Schema schema) internal pure returns (uint256) { + return uint256(uint16(bytes2(Schema.unwrap(schema)))); + } + + /** + * Get the type of the data for the given schema at the given index + */ + function atIndex(Schema schema, uint256 index) internal pure returns (SchemaType) { + return SchemaType(uint8(Bytes.slice1(Schema.unwrap(schema), index + 4))); + } + + /** + * Get the number of dynamic length fields for the given schema + */ + function numDynamicFields(Schema schema) internal pure returns (uint8) { + return uint8(Bytes.slice1(Schema.unwrap(schema), 3)); + } + + /** + * Get the number of static fields for the given schema + */ + function numStaticFields(Schema schema) internal pure returns (uint8) { + return uint8(Bytes.slice1(Schema.unwrap(schema), 2)); + } + + /** + * Check if the given schema is empty + */ + function isEmpty(Schema schema) internal pure returns (bool) { + return Schema.unwrap(schema) == bytes32(0); + } + + function validate(Schema schema) internal pure { + // Schema must not be empty + if (schema.isEmpty()) revert SchemaLib_InvalidLength(0); + + // Schema must have no more than 14 dynamic fields + uint256 _numDynamicFields = schema.numDynamicFields(); + if (_numDynamicFields > 14) revert SchemaLib_InvalidLength(_numDynamicFields); + + uint256 _numStaticFields = schema.numStaticFields(); + // Schema must not have more than 28 fields in total + if (_numStaticFields + _numDynamicFields > 28) revert SchemaLib_InvalidLength(_numStaticFields + _numDynamicFields); + + // No static field can be after a dynamic field + uint256 countStaticFields; + uint256 countDynamicFields; + for (uint256 i; i < _numStaticFields + _numDynamicFields; ) { + if (getStaticByteLength(schema.atIndex(i)) > 0) { + // Static field in dynamic part + if (i >= _numStaticFields) revert SchemaLib_StaticTypeAfterDynamicType(); + countStaticFields++; + } else { + // Dynamic field in static part + if (i < _numStaticFields) revert SchemaLib_StaticTypeAfterDynamicType(); + countDynamicFields++; + } + unchecked { + i++; + } + } + + // Number of static fields must match + if (countStaticFields != _numStaticFields) revert SchemaLib_InvalidLength(countStaticFields); + + // Number of dynamic fields must match + if (countDynamicFields != _numDynamicFields) revert SchemaLib_InvalidLength(countDynamicFields); + } + + /** + * Unwrap the schema + */ + function unwrap(Schema schema) internal pure returns (bytes32) { + return Schema.unwrap(schema); + } +} diff --git a/packages/store/src/Storage.sol b/packages/store/src/Storage.sol new file mode 100644 index 0000000000..146e7772f2 --- /dev/null +++ b/packages/store/src/Storage.sol @@ -0,0 +1,194 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import { console } from "forge-std/console.sol"; +import { Utils } from "./Utils.sol"; +import { Bytes } from "./Bytes.sol"; +import { Memory } from "./Memory.sol"; +import "./Buffer.sol"; + +library Storage { + function store(uint256 storagePointer, bytes memory data) internal { + store(storagePointer, 0, data); + } + + function store(uint256 storagePointer, bytes32 data) internal { + _storeWord(storagePointer, data); + } + + function store( + uint256 storagePointer, + uint256 offset, + bytes memory data + ) internal { + uint256 memoryPointer; + assembly { + memoryPointer := add(data, 0x20) + } + store(storagePointer, offset, memoryPointer, data.length); + } + + /** + * @notice Stores raw bytes to storage at the given storagePointer and offset (keeping the rest of the word intact) + * @dev This implementation is optimized for readability, but not very gas efficient. We should optimize this using assembly once we've settled on a spec. + */ + function store( + uint256 storagePointer, + uint256 offset, + uint256 memoryPointer, + uint256 length + ) internal { + // Support offsets that are greater than 32 bytes by incrementing the storagePointer and decrementing the offset + storagePointer += offset / 32; + offset %= 32; + + uint256 numWords = Utils.divCeil(length + offset, 32); + uint256 bytesWritten; + + for (uint256 i; i < numWords; i++) { + // If this is the first word, and there is an offset, apply a mask to beginning + if ((i == 0 && offset > 0)) { + uint256 _lengthTostore = length + offset > 32 ? 32 - offset : length; // // the number of bytes to store + _storePartialWord( + storagePointer, // the word to update + _lengthTostore, + offset, // the offset in bytes to start writing + Memory.load({ memoryPointer: memoryPointer }) // Pass the first 32 bytes of the data + ); + bytesWritten += _lengthTostore; + // If this is the last word, and there is a partial word, apply a mask to the end + } else if (i == numWords - 1 && (length + offset) % 32 > 0) { + _storePartialWord( + storagePointer + i, // the word to update + (length + offset) % 32, // the number of bytes to store + 0, // the offset in bytes to start writing + Memory.load({ memoryPointer: memoryPointer, offset: bytesWritten }) // the data to store + ); + + // Else, just store the word + } else { + _storeWord(storagePointer + i, Memory.load({ memoryPointer: memoryPointer, offset: bytesWritten })); + bytesWritten += 32; + } + } + } + + function load(uint256 storagePointer) internal view returns (bytes32) { + return _loadWord(storagePointer); + } + + function load(uint256 storagePointer, uint256 length) internal view returns (bytes memory) { + return load(storagePointer, length, 0); + } + + /** + * @notice Load raw bytes from storage at the given storagePointer, offset, and length + */ + function load( + uint256 storagePointer, + uint256 length, + uint256 offset + ) internal view returns (bytes memory) { + Buffer buffer = Buffer_.allocate(uint128(length)); + load(storagePointer, length, offset, buffer); + return buffer.toBytes(); + } + + /** + * @notice Append raw bytes from storage at the given storagePointer, offset, and length to the given buffer + */ + function load( + uint256 storagePointer, + uint256 length, + uint256 offset, + Buffer buffer + ) internal view { + // Support offsets that are greater than 32 bytes by incrementing the storagePointer and decrementing the offset + storagePointer += offset / 32; + offset %= 32; + + uint256 numWords = Utils.divCeil(length + offset, 32); + uint256 _lengthToload; + + for (uint256 i; i < numWords; i++) { + // If this is the first word, and there is an offset, apply a mask to beginning (and possibly the end if length + offset is less than 32) + if ((i == 0 && offset > 0)) { + _lengthToload = length + offset > 32 ? 32 - offset : length; // the number of bytes to load + buffer.appendUnchecked( + _loadPartialWord( + storagePointer, // the slot to start loading from + _lengthToload, + offset // the offset in bytes to start loading from + ), + uint128(_lengthToload) + ); + + // If this is the last word, and there is a partial word, apply a mask to the end + } else if (i == numWords - 1 && (length + offset) % 32 > 0) { + _lengthToload = (length + offset) % 32; // the relevant length of the trailing word + buffer.appendUnchecked( + _loadPartialWord( + storagePointer + i, // the word to load from + _lengthToload, + 0 // the offset in bytes to start loading from + ), + uint128(_lengthToload) + ); + + // Else, just load the word + } else { + buffer.appendUnchecked(_loadWord(storagePointer + i), 32); + } + } + } + + /** + * @notice Load a full word from storage into memory + */ + function _loadWord(uint256 storagePointer) internal view returns (bytes32 data) { + assembly { + data := sload(storagePointer) + } + } + + /** + * @notice Load a partial word from storage into memory + */ + function _loadPartialWord( + uint256 storagePointer, + uint256 length, + uint256 offset + ) internal view returns (bytes32) { + // Load current value from storage + bytes32 storageValue; + assembly { + storageValue := sload(storagePointer) + } + + // create a mask for the bits we want to update + return (storageValue << (offset * 8)) & bytes32(Utils.leftMask(length * 8)); + } + + function _storeWord(uint256 storagePointer, bytes32 data) internal { + assembly { + sstore(storagePointer, data) + } + } + + function _storePartialWord( + uint256 storagePointer, + uint256 length, // in bytes + uint256 offset, // in bytes + bytes32 data + ) internal { + bytes32 current; + assembly { + current := sload(storagePointer) + } + bytes32 mask = bytes32(Utils.leftMask(length * 8) >> (offset * 8)); // create a mask for the bits we want to update + bytes32 updated = (current & ~mask) | ((data >> (offset * 8)) & mask); // apply mask to data + assembly { + sstore(storagePointer, updated) + } + } +} diff --git a/packages/store/src/StoreCore.sol b/packages/store/src/StoreCore.sol new file mode 100644 index 0000000000..9d511deabc --- /dev/null +++ b/packages/store/src/StoreCore.sol @@ -0,0 +1,548 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; +import { Utils } from "./Utils.sol"; +import { Bytes } from "./Bytes.sol"; +import { SchemaType, getStaticByteLength, getElementByteLength } from "./Types.sol"; +import { Storage } from "./Storage.sol"; +import { Memory } from "./Memory.sol"; +import { console } from "forge-std/console.sol"; +import { Schema } from "./Schema.sol"; +import { PackedCounter } from "./PackedCounter.sol"; +import { Buffer, Buffer_ } from "./Buffer.sol"; +import { HooksTable, tableId as HooksTableId } from "./tables/HooksTable.sol"; +import { IStoreHook } from "./IStore.sol"; + +library StoreCore { + // note: the preimage of the tuple of keys used to index is part of the event, so it can be used by indexers + event MudStoreSetRecord(bytes32 table, bytes32[] key, bytes data); + event MudStoreSetField(bytes32 table, bytes32[] key, uint8 schemaIndex, bytes data); + event MudStoreDeleteRecord(bytes32 table, bytes32[] key); + + error StoreCore_TableAlreadyExists(bytes32 table); + error StoreCore_TableNotFound(bytes32 table); + error StoreCore_NotImplemented(); + error StoreCore_InvalidDataLength(uint256 expected, uint256 received); + error StoreCore_NoDynamicField(); + + /** + * Initialize internal tables. + * Consumers must call this function in their constructor. + * TODO: should we turn the schema table into a "proper table" and register it here? + */ + function initialize() internal { + registerSchema(HooksTableId, HooksTable.getSchema()); + } + + /************************************************************************ + * + * SCHEMA + * + ************************************************************************/ + + /** + * Check if the given table exists + */ + function hasTable(bytes32 table) internal view returns (bool) { + return !getSchema(table).isEmpty(); + } + + /** + * Register a new table schema + */ + function registerSchema(bytes32 table, Schema schema) internal { + // Verify the schema is valid + schema.validate(); + + // Verify the schema doesn't exist yet + if (hasTable(table)) { + revert StoreCore_TableAlreadyExists(table); + } + + // Register the schema + StoreCoreInternal._registerSchemaUnchecked(table, schema); + } + + /** + * Get the schema for the given table + */ + function getSchema(bytes32 table) internal view returns (Schema schema) { + return StoreCoreInternal._getSchema(table); + } + + /************************************************************************ + * + * REGISTER HOOKS + * + ************************************************************************/ + + /* + * Register hooks to be called when a record or field is set or deleted + */ + function registerHook(bytes32 table, IStoreHook hook) external { + HooksTable.push(table, address(hook)); + } + + /************************************************************************ + * + * SET DATA + * + ************************************************************************/ + + /** + * Set full data record for the given table and key tuple (static and dynamic data) + */ + function setRecord( + bytes32 table, + bytes32[] memory key, + bytes memory data + ) internal { + // verify the value has the correct length for the table (based on the table's schema) + // to prevent invalid data from being stored + Schema schema = getSchema(table); + + // Verify static data length + dynamic data length matches the given data + uint256 staticLength = schema.staticDataLength(); + uint256 expectedLength = staticLength; + PackedCounter dynamicLength; + if (schema.numDynamicFields() > 0) { + // Dynamic length is encoded at the start of the dynamic length blob + dynamicLength = PackedCounter.wrap(Bytes.slice32(data, staticLength)); + expectedLength += 32 + dynamicLength.total(); // encoded length + data + } + + if (expectedLength != data.length) { + revert StoreCore_InvalidDataLength(expectedLength, data.length); + } + + // Call onSetRecord hooks (before actually modifying the state, so observers have access to the previous state if needed) + address[] memory hooks = HooksTable.get(table); + for (uint256 i = 0; i < hooks.length; i++) { + IStoreHook hook = IStoreHook(hooks[i]); + hook.onSetRecord(table, key, data); + } + + // Store the static data at the static data location + uint256 staticDataLocation = StoreCoreInternal._getStaticDataLocation(table, key); + uint256 memoryPointer = Memory.dataPointer(data); + Storage.store({ + storagePointer: staticDataLocation, + offset: 0, + memoryPointer: memoryPointer, + length: staticLength + }); + memoryPointer += staticLength + 32; // move the memory pointer to the start of the dynamic data (skip the encoded dynamic length) + + // If there is no dynamic data, we're done + if (schema.numDynamicFields() == 0) return; + + // Store the dynamic data length at the dynamic data length location + uint256 dynamicDataLengthLocation = StoreCoreInternal._getDynamicDataLengthLocation(table, key); + Storage.store({ storagePointer: dynamicDataLengthLocation, data: dynamicLength.unwrap() }); + + // For every dynamic element, slice off the dynamic data and store it at the dynamic location + uint256 dynamicDataLocation; + uint256 dynamicDataLength; + for (uint8 i; i < schema.numDynamicFields(); ) { + dynamicDataLocation = StoreCoreInternal._getDynamicDataLocation(table, key, i); + dynamicDataLength = dynamicLength.atIndex(i); + Storage.store({ + storagePointer: dynamicDataLocation, + offset: 0, + memoryPointer: memoryPointer, + length: dynamicDataLength + }); + memoryPointer += dynamicDataLength; // move the memory pointer to the start of the next dynamic data + unchecked { + i++; + } + } + + // Emit event to notify indexers + emit MudStoreSetRecord(table, key, data); + } + + function setField( + bytes32 table, + bytes32[] memory key, + uint8 schemaIndex, + bytes memory data + ) internal { + Schema schema = getSchema(table); + + // Call onSetField hooks (before actually modifying the state, so observers have access to the previous state if needed) + address[] memory hooks = HooksTable.get(table); + for (uint256 i = 0; i < hooks.length; i++) { + IStoreHook hook = IStoreHook(hooks[i]); + hook.onSetField(table, key, schemaIndex, data); + } + + if (schemaIndex < schema.numStaticFields()) { + StoreCoreInternal._setStaticField(table, key, schema, schemaIndex, data); + } else { + StoreCoreInternal._setDynamicField(table, key, schema, schemaIndex, data); + } + + // Emit event to notify indexers + emit MudStoreSetField(table, key, schemaIndex, data); + } + + function deleteRecord(bytes32 table, bytes32[] memory key) internal { + // Get schema for this table + Schema schema = getSchema(table); + + // Call onDeleteRecord hooks (before actually modifying the state, so observers have access to the previous state if needed) + address[] memory hooks = HooksTable.get(table); + for (uint256 i = 0; i < hooks.length; i++) { + IStoreHook hook = IStoreHook(hooks[i]); + hook.onDeleteRecord(table, key); + } + + // Delete static data + uint256 staticDataLocation = StoreCoreInternal._getStaticDataLocation(table, key); + Storage.store({ storagePointer: staticDataLocation, offset: 0, data: new bytes(schema.staticDataLength()) }); + + // If there are no dynamic fields, we're done + if (schema.numDynamicFields() == 0) return; + + // Delete dynamic data length + uint256 dynamicDataLengthLocation = StoreCoreInternal._getDynamicDataLengthLocation(table, key); + Storage.store({ storagePointer: dynamicDataLengthLocation, data: bytes32(0) }); + + // Emit event to notify indexers + emit MudStoreDeleteRecord(table, key); + } + + /************************************************************************ + * + * GET DATA + * + ************************************************************************/ + + /** + * Get full record (all fields, static and dynamic data) for the given table and key tuple (loading schema from storage) + */ + function getRecord(bytes32 table, bytes32[] memory key) internal view returns (bytes memory) { + // Get schema for this table + Schema schema = getSchema(table); + if (schema.isEmpty()) revert StoreCore_TableNotFound(table); + + return getRecord(table, key, schema); + } + + /** + * Get full record (all fields, static and dynamic data) for the given table and key tuple, with the given schema + */ + function getRecord( + bytes32 table, + bytes32[] memory key, + Schema schema + ) internal view returns (bytes memory) { + // Get the static data length + uint256 outputLength = schema.staticDataLength(); + + // Load the dynamic data length if there are dynamic fields + PackedCounter dynamicDataLength; + uint256 numDynamicFields = schema.numDynamicFields(); + if (numDynamicFields > 0) { + dynamicDataLength = StoreCoreInternal._loadEncodedDynamicDataLength(table, key); + outputLength += 32 + dynamicDataLength.total(); // encoded length + data + } + + // Allocate a buffer for the full data (static and dynamic) + Buffer buffer = Buffer_.allocate(uint128(outputLength)); + + // Load the static data from storage and append it to the buffer + buffer.append(StoreCoreInternal._getStaticData(table, key, schema)); + + // Early return if there are no dynamic fields + if (dynamicDataLength.total() == 0) return buffer.toBytes(); + + // Append the encoded dynamic length to the buffer after the static data + buffer.append(dynamicDataLength.unwrap()); + + // Append dynamic data to the buffer + for (uint8 i; i < numDynamicFields; i++) { + uint256 dynamicDataLocation = uint256(StoreCoreInternal._getDynamicDataLocation(table, key, i)); + Storage.load({ + storagePointer: dynamicDataLocation, + length: dynamicDataLength.atIndex(i), + offset: 0, + buffer: buffer + }); + } + + // Return the buffer as bytes + return buffer.toBytes(); + } + + /** + * Get a single field from the given table and key tuple (loading schema from storage) + */ + function getField( + bytes32 table, + bytes32[] memory key, + uint8 schemaIndex + ) internal view returns (bytes memory) { + Schema schema = getSchema(table); + return getField(table, key, schemaIndex, schema); + } + + /** + * Get a single field from the given table and key tuple, with the given schema + */ + function getField( + bytes32 table, + bytes32[] memory key, + uint8 schemaIndex, + Schema schema + ) internal view returns (bytes memory) { + if (schemaIndex < schema.numStaticFields()) { + return StoreCoreInternal._getStaticField(table, key, schemaIndex, schema); + } else { + return StoreCoreInternal._getDynamicField(table, key, schemaIndex, schema); + } + } +} + +library StoreCoreInternal { + bytes32 internal constant SLOT = keccak256("mud.store"); + bytes32 internal constant SCHEMA_TABLE = keccak256("mud.store.table.schema"); + + error StoreCore_InvalidDataLength(uint256 expected, uint256 received); + + /************************************************************************ + * + * SCHEMA + * + ************************************************************************/ + + function _getSchema(bytes32 table) internal view returns (Schema) { + bytes32[] memory key = new bytes32[](1); + key[0] = table; + uint256 location = StoreCoreInternal._getStaticDataLocation(SCHEMA_TABLE, key); + return Schema.wrap(Storage.load({ storagePointer: location })); + } + + /** + * Register a new table schema without validity checks + */ + function _registerSchemaUnchecked(bytes32 table, Schema schema) internal { + bytes32[] memory key = new bytes32[](1); + key[0] = table; + uint256 location = _getStaticDataLocation(SCHEMA_TABLE, key); + Storage.store({ storagePointer: location, data: schema.unwrap() }); + } + + /************************************************************************ + * + * SET DATA + * + ************************************************************************/ + + function _setStaticField( + bytes32 table, + bytes32[] memory key, + Schema schema, + uint8 schemaIndex, + bytes memory data + ) internal { + // verify the value has the correct length for the field + SchemaType schemaType = schema.atIndex(schemaIndex); + if (getStaticByteLength(schemaType) != data.length) + revert StoreCore_InvalidDataLength(getStaticByteLength(schemaType), data.length); + + // Store the provided value in storage + uint256 location = _getStaticDataLocation(table, key); + uint256 offset = _getStaticDataOffset(schema, schemaIndex); + Storage.store({ storagePointer: location, offset: offset, data: data }); + } + + function _setDynamicField( + bytes32 table, + bytes32[] memory key, + Schema schema, + uint8 schemaIndex, + bytes memory data + ) internal { + uint8 dynamicSchemaIndex = schemaIndex - schema.numStaticFields(); + + // Update the dynamic data length + _setDynamicDataLengthAtIndex(table, key, dynamicSchemaIndex, data.length); + + // Store the provided value in storage + uint256 dynamicDataLocation = _getDynamicDataLocation(table, key, dynamicSchemaIndex); + Storage.store({ storagePointer: dynamicDataLocation, data: data }); + } + + /************************************************************************ + * + * GET DATA + * + ************************************************************************/ + + /** + * Get full static record for the given table and key tuple (loading schema from storage) + */ + function _getStaticData(bytes32 table, bytes32[] memory key) internal view returns (bytes memory) { + Schema schema = _getSchema(table); + return _getStaticData(table, key, schema); + } + + /** + * Get full static data for the given table and key tuple, with the given schema + */ + function _getStaticData( + bytes32 table, + bytes32[] memory key, + Schema schema + ) internal view returns (bytes memory) { + if (schema.staticDataLength() == 0) return new bytes(0); + + // Load the data from storage + uint256 location = _getStaticDataLocation(table, key); + return Storage.load({ storagePointer: location, length: schema.staticDataLength() }); + } + + /** + * Get a single static field from the given table and key tuple, with the given schema + */ + function _getStaticField( + bytes32 table, + bytes32[] memory key, + uint8 schemaIndex, + Schema schema + ) internal view returns (bytes memory) { + // Get the length, storage location and offset of the static field + SchemaType schemaType = schema.atIndex(schemaIndex); + uint256 dataLength = getStaticByteLength(schemaType); + uint256 location = uint256(_getStaticDataLocation(table, key)); + uint256 offset = _getStaticDataOffset(schema, schemaIndex); + + // Load the data from storage + + return Storage.load({ storagePointer: location, length: dataLength, offset: offset }); + } + + /** + * Get a single dynamic field from the given table and key tuple, with the given schema + */ + function _getDynamicField( + bytes32 table, + bytes32[] memory key, + uint8 schemaIndex, + Schema schema + ) internal view returns (bytes memory) { + // Get the length and storage location of the dynamic field + uint8 dynamicSchemaIndex = schemaIndex - schema.numStaticFields(); + uint256 location = _getDynamicDataLocation(table, key, dynamicSchemaIndex); + uint256 dataLength = _loadEncodedDynamicDataLength(table, key).atIndex(dynamicSchemaIndex); + + return Storage.load({ storagePointer: location, length: dataLength }); + } + + /************************************************************************ + * + * HELPER FUNCTIONS + * + ************************************************************************/ + + ///////////////////////////////////////////////////////////////////////// + // STATIC DATA + ///////////////////////////////////////////////////////////////////////// + + /** + * Compute the storage location based on table id and index tuple + */ + function _getStaticDataLocation(bytes32 table, bytes32[] memory key) internal pure returns (uint256) { + return uint256(keccak256(abi.encode(SLOT, table, key))); + } + + /** + * Get storage offset for the given schema and (static length) index + */ + function _getStaticDataOffset(Schema schema, uint8 schemaIndex) internal pure returns (uint256) { + uint256 offset = 0; + for (uint256 i = 0; i < schemaIndex; i++) { + offset += getStaticByteLength(schema.atIndex(i)); + } + return offset; + } + + ///////////////////////////////////////////////////////////////////////// + // DYNAMIC DATA + ///////////////////////////////////////////////////////////////////////// + + /** + * Compute the storage location based on table id and index tuple + */ + function _getDynamicDataLocation( + bytes32 table, + bytes32[] memory key, + uint8 schemaIndex + ) internal pure returns (uint256) { + return uint256(keccak256(abi.encode(SLOT, table, key, schemaIndex))); + } + + /** + * Compute the storage location for the length of the dynamic data + */ + function _getDynamicDataLengthLocation(bytes32 table, bytes32[] memory key) internal pure returns (uint256) { + return uint256(keccak256(abi.encode(SLOT, table, key, "length"))); + } + + /** + * Get the length of the dynamic data for the given schema and index + */ + function _loadEncodedDynamicDataLength(bytes32 table, bytes32[] memory key) internal view returns (PackedCounter) { + // Load dynamic data length from storage + uint256 dynamicSchemaLengthSlot = _getDynamicDataLengthLocation(table, key); + return PackedCounter.wrap(Storage.load({ storagePointer: dynamicSchemaLengthSlot })); + } + + /** + * Set the length of the dynamic data (in bytes) for the given schema and index + */ + function _setDynamicDataLengthAtIndex( + bytes32 table, + bytes32[] memory key, + uint8 dynamicSchemaIndex, // schemaIndex - numStaticFields + uint256 newLengthAtIndex + ) internal { + // Load dynamic data length from storage + uint256 dynamicSchemaLengthSlot = _getDynamicDataLengthLocation(table, key); + PackedCounter encodedLengths = PackedCounter.wrap(Storage.load({ storagePointer: dynamicSchemaLengthSlot })); + + // Update the encoded lengths + encodedLengths = encodedLengths.setAtIndex(dynamicSchemaIndex, newLengthAtIndex); + + // Set the new lengths + Storage.store({ storagePointer: dynamicSchemaLengthSlot, data: encodedLengths.unwrap() }); + } +} + +// Overloads for single key and some fixed length array keys for better devex +library StoreCoreExtended { + /************************************************************************ + * + * SET DATA + * + ************************************************************************/ + + /************************************************************************ + * + * GET DATA + * + ************************************************************************/ + function getRecord(bytes32 table, bytes32 _key) external view returns (bytes memory) { + bytes32[] memory key = new bytes32[](1); + key[0] = _key; + return StoreCore.getRecord(table, key); + } + + function getData(bytes32 table, bytes32[2] memory _key) external view returns (bytes memory) { + bytes32[] memory key = new bytes32[](2); + key[0] = _key[0]; + key[1] = _key[1]; + return StoreCore.getRecord(table, key); + } +} diff --git a/packages/store/src/StoreSwitch.sol b/packages/store/src/StoreSwitch.sol new file mode 100644 index 0000000000..cc666b7512 --- /dev/null +++ b/packages/store/src/StoreSwitch.sol @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import { console } from "forge-std/console.sol"; +import { SchemaType } from "./Types.sol"; +import { IStore } from "./IStore.sol"; +import { StoreCore } from "./StoreCore.sol"; +import { Schema } from "./Schema.sol"; + +/** + * Call IStore functions on self or msg.sender, depending on whether the call is a delegatecall or regular call. + */ +library StoreSwitch { + error StoreSwitch_InvalidInsideConstructor(); + + /** + * Detect whether the current call is a delegatecall or regular call. + * (The isStore method doesn't return a value to save gas, but it if exists, the call will succeed.) + */ + function isDelegateCall() internal view returns (bool success) { + // Detect calls from within a constructor and revert to avoid unexpected behavior + uint256 codeSize; + assembly { + codeSize := extcodesize(address()) + } + if (codeSize == 0) revert StoreSwitch_InvalidInsideConstructor(); + + // Check whether this contract implements the IStore interface + try IStore(address(this)).isStore() { + success = true; + } catch { + success = false; + } + } + + function registerSchema(bytes32 table, Schema schema) internal { + if (isDelegateCall()) { + StoreCore.registerSchema(table, schema); + } else { + IStore(msg.sender).registerSchema(table, schema); + } + } + + function getSchema(bytes32 table) internal view returns (Schema schema) { + if (isDelegateCall()) { + schema = StoreCore.getSchema(table); + } else { + schema = IStore(msg.sender).getSchema(table); + } + } + + function setRecord( + bytes32 table, + bytes32[] memory key, + bytes memory data + ) internal { + if (isDelegateCall()) { + StoreCore.setRecord(table, key, data); + } else { + IStore(msg.sender).setRecord(table, key, data); + } + } + + function setField( + bytes32 table, + bytes32[] memory key, + uint8 fieldIndex, + bytes memory data + ) internal { + if (isDelegateCall()) { + StoreCore.setField(table, key, fieldIndex, data); + } else { + IStore(msg.sender).setField(table, key, fieldIndex, data); + } + } + + function deleteRecord(bytes32 table, bytes32[] memory key) internal { + if (isDelegateCall()) { + StoreCore.deleteRecord(table, key); + } else { + IStore(msg.sender).deleteRecord(table, key); + } + } + + function getRecord(bytes32 table, bytes32[] memory key) internal view returns (bytes memory) { + if (isDelegateCall()) { + return StoreCore.getRecord(table, key); + } else { + return IStore(msg.sender).getRecord(table, key); + } + } + + function getRecord( + bytes32 table, + bytes32[] memory key, + Schema schema + ) internal view returns (bytes memory) { + if (isDelegateCall()) { + return StoreCore.getRecord(table, key, schema); + } else { + return IStore(msg.sender).getRecord(table, key, schema); + } + } + + function getField( + bytes32 table, + bytes32[] memory key, + uint8 fieldIndex + ) internal view returns (bytes memory) { + if (isDelegateCall()) { + return StoreCore.getField(table, key, fieldIndex); + } else { + return IStore(msg.sender).getField(table, key, fieldIndex); + } + } +} diff --git a/packages/store/src/StoreView.sol b/packages/store/src/StoreView.sol new file mode 100644 index 0000000000..4dad55d2ca --- /dev/null +++ b/packages/store/src/StoreView.sol @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import { SchemaType } from "./Types.sol"; +import { IStore, IStoreHook } from "./IStore.sol"; +import { StoreCore } from "./StoreCore.sol"; +import { Schema } from "./Schema.sol"; + +// Not abstract, so that it can be used as a base contract for testing and wherever write access is not needed +contract StoreView is IStore { + error StoreView_NotImplemented(); + + constructor() { + StoreCore.initialize(); + } + + function getSchema(bytes32 table) public view virtual returns (Schema schema) { + schema = StoreCore.getSchema(table); + } + + function registerSchema(bytes32, Schema) public virtual { + revert StoreView_NotImplemented(); + } + + function setRecord( + bytes32, + bytes32[] memory, + bytes memory + ) public virtual { + revert StoreView_NotImplemented(); + } + + // Set partial data at schema index + function setField( + bytes32, + bytes32[] memory, + uint8, + bytes memory + ) public virtual { + revert StoreView_NotImplemented(); + } + + function registerHook(bytes32, IStoreHook) public virtual { + revert StoreView_NotImplemented(); + } + + function deleteRecord(bytes32, bytes32[] memory) public virtual { + revert StoreView_NotImplemented(); + } + + // Get full record (including full array, load schema from storage) + function getRecord(bytes32 table, bytes32[] memory key) public view virtual returns (bytes memory data) { + data = StoreCore.getRecord(table, key); + } + + // Get full record (including full array) + function getRecord( + bytes32 table, + bytes32[] memory key, + Schema schema + ) public view virtual returns (bytes memory data) { + data = StoreCore.getRecord(table, key, schema); + } + + // Get partial data at schema index + function getField( + bytes32 table, + bytes32[] memory key, + uint8 schemaIndex + ) public view virtual returns (bytes memory data) { + data = StoreCore.getField(table, key, schemaIndex); + } + + function isStore() public view {} +} diff --git a/packages/store/src/System.sol b/packages/store/src/System.sol new file mode 100644 index 0000000000..1fce49db82 --- /dev/null +++ b/packages/store/src/System.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +contract System { + // Extract the trusted msg.sender value appended to the calldata + function _msgSender() internal pure returns (address sender) { + assembly { + // 96 = 256 - 20 * 8 + sender := shr(96, calldataload(sub(calldatasize(), 20))) + } + } +} diff --git a/packages/store/src/Types.sol b/packages/store/src/Types.sol new file mode 100644 index 0000000000..f86029a8ba --- /dev/null +++ b/packages/store/src/Types.sol @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +// TODO: add remaining types +enum SchemaType { + None, // The first `None` value ends the schema + Uint8, + Uint16, + Uint32, + Uint128, + Uint256, + Bytes4, + Uint32Array, + Bytes24Array, + String, + Address, + AddressArray +} + +/** + * Get the length of the data for the given schema type + * (Because Solidity doesn't support constant arrays, we need to use a function) + * TODO: add more types and make it more efficient (avoid linear search) + */ +function getStaticByteLength(SchemaType schemaType) pure returns (uint256) { + if (schemaType == SchemaType.Uint8) { + return 1; + } else if (schemaType == SchemaType.Uint16) { + return 2; + } else if (schemaType == SchemaType.Uint32 || schemaType == SchemaType.Bytes4) { + return 4; + } else if (schemaType == SchemaType.Uint128) { + return 16; + } else if (schemaType == SchemaType.Uint256) { + return 32; + } else if (schemaType == SchemaType.Address) { + return 20; + } else { + // Return 0 for all dynamic types + return 0; + } +} + +function getElementByteLength(SchemaType schemaType) pure returns (uint256) { + if (schemaType == SchemaType.Uint32Array) { + return 4; + } else if (schemaType == SchemaType.Uint32Array) { + return 1; + } else if (schemaType == SchemaType.Bytes24Array) { + return 24; + } else { + return getStaticByteLength(schemaType); + } +} + +/** + * Returns true if the schema type has a fixed length + * (Because Solidity doesn't support constant arrays, we need to use a function) + * TODO: add more types and make it more efficient (avoid linear search) + */ +function hasStaticLength(SchemaType schemaType) pure returns (bool) { + if (schemaType == SchemaType.Uint8) { + return true; + } else if (schemaType == SchemaType.Uint16) { + return true; + } else if (schemaType == SchemaType.Uint32) { + return true; + } else if (schemaType == SchemaType.Uint128) { + return true; + } else if (schemaType == SchemaType.Uint256) { + return true; + } else if (schemaType == SchemaType.Bytes4) { + return true; + } else if (schemaType == SchemaType.Address) { + return true; + } else { + return false; + } +} + +enum ExecutionMode { + Delegate, + Autonomous +} diff --git a/packages/store/src/Utils.sol b/packages/store/src/Utils.sol new file mode 100644 index 0000000000..6209c585f9 --- /dev/null +++ b/packages/store/src/Utils.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +library Utils { + function divCeil(uint256 a, uint256 b) internal pure returns (uint256) { + return a / b + (a % b == 0 ? 0 : 1); + } + + /** + * Adapted from https://github.com/dk1a/solidity-stringutils/blob/main/src/utils/mem.sol#L149-L167 + * @dev Left-aligned bit mask (e.g. for partial mload/mstore). + * For length >= 32 returns type(uint256).max + */ + function leftMask(uint256 bitLength) internal pure returns (uint256) { + unchecked { + return ~(type(uint256).max >> (bitLength)); + } + } +} diff --git a/packages/store/src/World.sol b/packages/store/src/World.sol new file mode 100644 index 0000000000..0ef4a14604 --- /dev/null +++ b/packages/store/src/World.sol @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import { console } from "forge-std/console.sol"; +import { StoreCore } from "./StoreCore.sol"; +import { StoreView } from "./StoreView.sol"; +import { SchemaType, ExecutionMode } from "./Types.sol"; +import { RouteTable, Route, tableId as RouteId } from "./tables/RouteTable.sol"; +import { Bytes } from "./Bytes.sol"; +import { Schema } from "./Schema.sol"; + +/** + * TODO: add access control + */ +contract World is StoreView { + error World_InvalidSystem(); + + constructor() { + registerSchema(RouteId, RouteTable.getSchema()); + } + + function registerSchema(bytes32 table, Schema schema) public override { + StoreCore.registerSchema(table, schema); + } + + function setRecord( + bytes32 table, + bytes32[] memory key, + bytes memory data + ) public override { + StoreCore.setRecord(table, key, data); + } + + function setField( + bytes32 table, + bytes32[] memory key, + uint8 schemaIndex, + bytes memory data + ) public override { + StoreCore.setField(table, key, schemaIndex, data); + } + + function registerSystem( + address contractAddress, + string memory contractName, + string memory functionSig, + ExecutionMode executionMode + ) public { + // TODO: checks + bytes4 worldSelector = bytes4(keccak256(abi.encodePacked(contractName, "_", functionSig))); + bytes4 funcSelector = bytes4(keccak256(abi.encodePacked(functionSig))); + RouteTable.set(bytes32(worldSelector), contractAddress, funcSelector, uint8(executionMode)); + } + + fallback() external payable { + // Find system by generated function selector + Route memory route = RouteTable.get(bytes32(msg.sig)); + + address addr = route.addr; + bytes4 selector = route.selector; + + if (addr == address(0)) revert World_InvalidSystem(); + + // Call the system function via `call` if the system is autonomous + if (route.executionMode == uint8(ExecutionMode.Autonomous)) { + assembly { + // place system function selector at memory position 0 + mstore(0, selector) + + // place existing calldata (exclusing selector) after system function selector + calldatacopy(4, 4, sub(calldatasize(), 4)) + + // place msg.sender after calldata + mstore(calldatasize(), caller()) + + // execute function call using the system and pass the constructed calldata + let result := call(gas(), addr, callvalue(), 0, add(calldatasize(), 32), 0, 0) + + // place any return value into memory at position 0 + returndatacopy(0, 0, returndatasize()) + + // return any return value or error back to the caller + switch result + case 0 { + revert(0, returndatasize()) + } + default { + return(0, returndatasize()) + } + } + } + + // Call the system function via `delegatecall` if the system is autonomous + if (route.executionMode == uint8(ExecutionMode.Delegate)) { + assembly { + // place system function selector at memory position 0 + mstore(0, selector) + + // place existing calldata (exclusing selector) after system function selector + calldatacopy(4, 4, sub(calldatasize(), 4)) + + // place msg.sender after calldata + mstore(calldatasize(), caller()) + + // execute function call using the system and pass the constructed calldata + let result := delegatecall(gas(), addr, 0, add(calldatasize(), 32), 0, 0) + + // place any return value into memory at position 0 + returndatacopy(0, 0, returndatasize()) + + // return any return value or error back to the caller + switch result + case 0 { + revert(0, returndatasize()) + } + default { + return(0, returndatasize()) + } + } + } + } +} diff --git a/packages/store/src/schemas/AddressArray.sol b/packages/store/src/schemas/AddressArray.sol new file mode 100644 index 0000000000..73566f12d1 --- /dev/null +++ b/packages/store/src/schemas/AddressArray.sol @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import { console } from "forge-std/console.sol"; +import { IStore } from "../IStore.sol"; +import { StoreSwitch } from "../StoreSwitch.sol"; +import { StoreCore } from "../StoreCore.sol"; +import { SchemaType } from "../Types.sol"; +import { Bytes } from "../Bytes.sol"; +import { Schema, SchemaLib } from "../Schema.sol"; +import { PackedCounter, PackedCounterLib } from "../PackedCounter.sol"; + +// -- User defined schema and tableId -- +struct AddressArray { + address[] addresses; +} + +// -- Autogenerated library to interact with tables with this schema -- +// TODO: autogenerate + +library AddressArray_ { + /** Get the table's schema */ + function getSchema() internal pure returns (Schema schema) { + schema = SchemaLib.encode(SchemaType.AddressArray); + } + + /** Register the table's schema */ + function registerSchema(bytes32 tableId) internal { + StoreSwitch.registerSchema(tableId, getSchema()); + } + + function registerSchema(bytes32 tableId, IStore store) internal { + store.registerSchema(tableId, getSchema()); + } + + /** Set the table's data */ + function set( + bytes32 tableId, + bytes32 key, + address[] memory addresses + ) internal { + bytes memory data = Bytes.from(addresses); + bytes32[] memory keyTuple = new bytes32[](1); + keyTuple[0] = key; + StoreSwitch.setField(tableId, keyTuple, 0, data); + } + + /** + * Push an element to the addresses array + * TODO: this is super inefficient right now, need to add support for pushing to arrays to the store core library to avoid reading/writing the entire array + */ + function push( + bytes32 tableId, + bytes32 key, + address addr + ) internal { + bytes32[] memory keyTuple = new bytes32[](1); + keyTuple[0] = key; + bytes memory addresses = abi.encodePacked(StoreSwitch.getField(tableId, keyTuple, 0), addr); + StoreSwitch.setField(tableId, keyTuple, 0, addresses); + } + + /** Get the table's data */ + function get(bytes32 tableId, bytes32 key) internal view returns (address[] memory addresses) { + bytes32[] memory keyTuple = new bytes32[](1); + keyTuple[0] = key; + bytes memory blob = StoreSwitch.getRecord(tableId, keyTuple); + return decode(blob); + } + + function get( + bytes32 tableId, + IStore store, + bytes32 key + ) internal view returns (address[] memory addresses) { + bytes32[] memory keyTuple = new bytes32[](1); + keyTuple[0] = key; + bytes memory blob = store.getRecord(tableId, keyTuple); + return decode(blob); + } + + function decode(bytes memory blob) internal pure returns (address[] memory addresses) { + if (blob.length == 0) return new address[](0); + return Bytes.toAddressArray(Bytes.slice(blob, 32, blob.length - 32)); + } +} diff --git a/packages/store/src/schemas/CallbackArray.sol b/packages/store/src/schemas/CallbackArray.sol new file mode 100644 index 0000000000..21adb02b9c --- /dev/null +++ b/packages/store/src/schemas/CallbackArray.sol @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import { console } from "forge-std/console.sol"; +import { IStore } from "../IStore.sol"; +import { StoreSwitch } from "../StoreSwitch.sol"; +import { StoreCore } from "../StoreCore.sol"; +import { SchemaType } from "../Types.sol"; +import { Bytes } from "../Bytes.sol"; +import { Schema, SchemaLib } from "../Schema.sol"; +import { PackedCounter, PackedCounterLib } from "../PackedCounter.sol"; + +// -- User defined schema and tableId -- +struct CallbackArray { + bytes24[] callbacks; +} + +// -- Autogenerated library to interact with tables with this schema -- +// TODO: autogenerate + +library CallbackArray_ { + /** Get the table's schema */ + function getSchema() internal pure returns (Schema schema) { + schema = SchemaLib.encode(SchemaType.Bytes24Array); + } + + /** Register the table's schema */ + function registerSchema(bytes32 tableId) internal { + StoreSwitch.registerSchema(tableId, getSchema()); + } + + function registerSchema(bytes32 tableId, IStore store) internal { + store.registerSchema(tableId, getSchema()); + } + + /** Set the table's data */ + function set( + bytes32 tableId, + bytes32 key, + bytes24[] memory callbacks + ) internal { + bytes memory data = Bytes.from(callbacks); + bytes32[] memory keyTuple = new bytes32[](1); + keyTuple[0] = key; + StoreSwitch.setField(tableId, keyTuple, 0, data); + } + + /** + * Push an element to the callbacks array + * TODO: this is super inefficient right now, need to add support for pushing to arrays to the store core library to avoid reading/writing the entire array + */ + function push( + bytes32 tableId, + bytes32 key, + bytes24 callback + ) internal { + bytes32[] memory keyTuple = new bytes32[](1); + keyTuple[0] = key; + bytes memory callbacks = abi.encodePacked(StoreSwitch.getField(tableId, keyTuple, 0), callback); + StoreSwitch.setField(tableId, keyTuple, 0, callbacks); + } + + /** Get the table's data */ + function get(bytes32 tableId, bytes32 key) internal view returns (bytes24[] memory callbacks) { + bytes32[] memory keyTuple = new bytes32[](1); + keyTuple[0] = key; + bytes memory blob = StoreSwitch.getRecord(tableId, keyTuple); + return decode(blob); + } + + function get( + bytes32 tableId, + IStore store, + bytes32 key + ) internal view returns (bytes24[] memory callbacks) { + bytes32[] memory keyTuple = new bytes32[](1); + keyTuple[0] = key; + bytes memory blob = store.getRecord(tableId, keyTuple); + return decode(blob); + } + + function decode(bytes memory blob) internal pure returns (bytes24[] memory callbacks) { + return Bytes.toBytes24Array(Bytes.slice(blob, 32, blob.length - 32)); + } +} diff --git a/packages/store/src/schemas/Mixed.sol b/packages/store/src/schemas/Mixed.sol new file mode 100644 index 0000000000..103cf00207 --- /dev/null +++ b/packages/store/src/schemas/Mixed.sol @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import { console } from "forge-std/console.sol"; +import { IStore } from "../IStore.sol"; +import { StoreSwitch } from "../StoreSwitch.sol"; +import { StoreCore } from "../StoreCore.sol"; +import { SchemaType } from "../Types.sol"; +import { Bytes } from "../Bytes.sol"; +import { Schema, SchemaLib } from "../Schema.sol"; +import { PackedCounter, PackedCounterLib } from "../PackedCounter.sol"; + +// -- User defined schema -- + +struct Mixed { + uint32 u32; + uint128 u128; + uint32[] a32; + string s; +} + +// -- Autogenerated library -- +// TODO: autogenerate + +library Mixed_ { + /** Get the table's schema */ + function getSchema() internal pure returns (Schema schema) { + schema = SchemaLib.encode(SchemaType.Uint32, SchemaType.Uint128, SchemaType.Uint32Array, SchemaType.String); + } + + /** Register the table's schema */ + function registerSchema(bytes32 tableId) internal { + StoreSwitch.registerSchema(tableId, getSchema()); + } + + function registerSchema(bytes32 tableId, IStore store) internal { + store.registerSchema(tableId, getSchema()); + } + + /** Set the table's data */ + function set( + bytes32 tableId, + bytes32 key, + uint32 u32, + uint128 u128, + uint32[] memory a32, + string memory s + ) internal { + PackedCounter encodedLengths = PackedCounterLib.pack(uint16(a32.length * 4), uint16(bytes(s).length)); + + bytes memory data = abi.encodePacked(u32, u128, encodedLengths.unwrap(), Bytes.from(a32), bytes(s)); + + bytes32[] memory keyTuple = new bytes32[](1); + keyTuple[0] = key; + + StoreSwitch.setRecord(tableId, keyTuple, data); + } + + function set( + bytes32 tableId, + bytes32 key, + Mixed memory mixed + ) internal { + set(tableId, key, mixed.u32, mixed.u128, mixed.a32, mixed.s); + } + + function setU32( + bytes32 tableId, + bytes32 key, + uint32 u32 + ) internal { + bytes32[] memory keyTuple = new bytes32[](1); + keyTuple[0] = key; + StoreSwitch.setField(tableId, keyTuple, 0, abi.encodePacked(u32)); + } + + function setU128( + bytes32 tableId, + bytes32 key, + uint128 u128 + ) internal { + bytes32[] memory keyTuple = new bytes32[](1); + keyTuple[0] = key; + StoreSwitch.setField(tableId, keyTuple, 1, abi.encodePacked(u128)); + } + + function setA32( + bytes32 tableId, + bytes32 key, + uint32[] memory a32 + ) internal { + bytes32[] memory keyTuple = new bytes32[](1); + keyTuple[0] = key; + StoreSwitch.setField(tableId, keyTuple, 2, Bytes.from(a32)); + } + + function setS( + bytes32 tableId, + bytes32 key, + string memory s + ) internal { + bytes32[] memory keyTuple = new bytes32[](1); + keyTuple[0] = key; + StoreSwitch.setField(tableId, keyTuple, 3, bytes(s)); + } + + /** Get the table's data */ + function get(bytes32 tableId, bytes32 key) internal view returns (Mixed memory mixed) { + bytes32[] memory keyTuple = new bytes32[](1); + keyTuple[0] = key; + bytes memory blob = StoreSwitch.getRecord(tableId, keyTuple, getSchema()); + return decode(blob); + } + + function get( + bytes32 tableId, + IStore store, + bytes32 key + ) internal view returns (Mixed memory mixed) { + bytes32[] memory keyTuple = new bytes32[](1); + keyTuple[0] = key; + bytes memory blob = store.getRecord(tableId, keyTuple); + return decode(blob); + } + + function decode(bytes memory blob) internal pure returns (Mixed memory mixed) { + PackedCounter encodedLengths = PackedCounter.wrap((Bytes.slice32(blob, 20))); // 20 = 4 + 16 (static data length) + + return + Mixed({ + u32: uint32(Bytes.slice4(blob, 0)), + u128: uint128(Bytes.slice16(blob, 4)), + a32: Bytes.toUint32Array(Bytes.slice(blob, 52, encodedLengths.atIndex(0))), + s: string(Bytes.slice(blob, 52 + encodedLengths.atIndex(0), encodedLengths.atIndex(1))) + }); + } +} diff --git a/packages/store/src/schemas/Route.sol b/packages/store/src/schemas/Route.sol new file mode 100644 index 0000000000..6e07ab5984 --- /dev/null +++ b/packages/store/src/schemas/Route.sol @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import { console } from "forge-std/console.sol"; +import { IStore } from "../IStore.sol"; +import { StoreSwitch } from "../StoreSwitch.sol"; +import { StoreCore } from "../StoreCore.sol"; +import { SchemaType } from "../Types.sol"; +import { Bytes } from "../Bytes.sol"; +import { Schema, SchemaLib } from "../Schema.sol"; + +// -- User defined schema -- + +struct Route { + address addr; + bytes4 selector; + uint8 executionMode; +} + +// -- Autogenerated library -- +// TODO: autogenerate + +library Route_ { + /** Get the table's schema */ + function getSchema() internal pure returns (Schema schema) { + schema = SchemaLib.encode(SchemaType.Address, SchemaType.Bytes4, SchemaType.Uint8); + } + + /** Register the table's schema */ + function registerSchema(bytes32 tableId) internal { + StoreSwitch.registerSchema(tableId, getSchema()); + } + + function registerSchema(bytes32 tableId, IStore store) internal { + store.registerSchema(tableId, getSchema()); + } + + /** Set the table's data */ + function set( + bytes32 tableId, + bytes32 key, + address addr, + bytes4 selector, + uint8 executionMode + ) internal { + bytes memory data = abi.encodePacked(addr, selector, executionMode); + bytes32[] memory keyTuple = new bytes32[](1); + keyTuple[0] = key; + StoreSwitch.setRecord(tableId, keyTuple, data); + } + + function set( + bytes32 tableId, + bytes32 key, + Route memory data + ) internal { + set(tableId, key, data.addr, data.selector, data.executionMode); + } + + function setAddress( + bytes32 tableId, + bytes32 key, + address addr + ) internal { + bytes32[] memory keyTuple = new bytes32[](1); + keyTuple[0] = key; + StoreSwitch.setField(tableId, keyTuple, 0, abi.encodePacked(addr)); + } + + function setSelector( + bytes32 tableId, + bytes32 key, + bytes4 selector + ) internal { + bytes32[] memory keyTuple = new bytes32[](1); + keyTuple[0] = key; + StoreSwitch.setField(tableId, keyTuple, 1, abi.encodePacked(selector)); + } + + function setExecutionMode( + bytes32 tableId, + bytes32 key, + uint8 executionMode + ) internal { + bytes32[] memory keyTuple = new bytes32[](1); + keyTuple[0] = key; + StoreSwitch.setField(tableId, keyTuple, 2, abi.encodePacked(executionMode)); + } + + /** Get the table's data */ + function get(bytes32 tableId, bytes32 key) internal view returns (Route memory data) { + bytes32[] memory keyTuple = new bytes32[](1); + keyTuple[0] = key; + bytes memory blob = StoreSwitch.getRecord(tableId, keyTuple); + return decode(blob); + } + + function get( + bytes32 tableId, + IStore store, + bytes32 key + ) internal view returns (Route memory data) { + bytes32[] memory keyTuple = new bytes32[](1); + keyTuple[0] = key; + bytes memory blob = store.getRecord(tableId, keyTuple); + return decode(blob); + } + + function decode(bytes memory blob) internal pure returns (Route memory data) { + return + Route({ + addr: address(Bytes.slice20(blob, 0)), + selector: Bytes.slice4(blob, 20), + executionMode: uint8(Bytes.slice1(blob, 24)) + }); + } +} diff --git a/packages/store/src/schemas/Vector2.sol b/packages/store/src/schemas/Vector2.sol new file mode 100644 index 0000000000..64c3648f58 --- /dev/null +++ b/packages/store/src/schemas/Vector2.sol @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import { console } from "forge-std/console.sol"; +import { IStore } from "../IStore.sol"; +import { StoreSwitch } from "../StoreSwitch.sol"; +import { StoreCore } from "../StoreCore.sol"; +import { SchemaType } from "../Types.sol"; +import { Bytes } from "../Bytes.sol"; +import { Schema, SchemaLib } from "../Schema.sol"; + +// -- User defined schema -- + +struct Vector2 { + uint32 x; + uint32 y; +} + +// -- Autogenerated library -- +// TODO: autogenerate + +library Vector2_ { + /** Get the table's schema */ + function getSchema() internal pure returns (Schema schema) { + schema = SchemaLib.encode(SchemaType.Uint32, SchemaType.Uint32); + } + + /** Register the table's schema */ + function registerSchema(bytes32 tableId) internal { + StoreSwitch.registerSchema(tableId, getSchema()); + } + + function registerSchema(bytes32 tableId, IStore store) internal { + store.registerSchema(tableId, getSchema()); + } + + /** Set the table's data */ + function set( + bytes32 tableId, + bytes32 key, + uint32 x, + uint32 y + ) internal { + bytes memory data = abi.encodePacked(x, y); + bytes32[] memory keyTuple = new bytes32[](1); + keyTuple[0] = key; + StoreSwitch.setRecord(tableId, keyTuple, data); + } + + function set( + bytes32 tableId, + bytes32 key, + Vector2 memory vec2 + ) internal { + set(tableId, key, vec2.x, vec2.y); + } + + function setX( + bytes32 tableId, + bytes32 key, + uint32 x + ) internal { + bytes32[] memory keyTuple = new bytes32[](1); + keyTuple[0] = key; + StoreSwitch.setField(tableId, keyTuple, 0, abi.encodePacked(x)); + } + + function setY( + bytes32 tableId, + bytes32 key, + uint32 y + ) internal { + bytes32[] memory keyTuple = new bytes32[](1); + keyTuple[0] = key; + StoreSwitch.setField(tableId, keyTuple, 1, abi.encodePacked(y)); + } + + /** Get the table's data */ + function get(bytes32 tableId, bytes32 key) internal view returns (Vector2 memory vec2) { + bytes32[] memory keyTuple = new bytes32[](1); + keyTuple[0] = key; + bytes memory blob = StoreSwitch.getRecord(tableId, keyTuple); + return decode(blob); + } + + function get( + bytes32 tableId, + IStore store, + bytes32 key + ) internal view returns (Vector2 memory vec2) { + bytes32[] memory keyTuple = new bytes32[](1); + keyTuple[0] = key; + bytes memory blob = store.getRecord(tableId, keyTuple); + return decode(blob); + } + + function decode(bytes memory blob) internal pure returns (Vector2 memory vec2) { + return Vector2({ x: uint32(Bytes.slice4(blob, 0)), y: uint32(Bytes.slice4(blob, 4)) }); + } +} diff --git a/packages/store/src/tables/HooksTable.sol b/packages/store/src/tables/HooksTable.sol new file mode 100644 index 0000000000..8926ebc1b4 --- /dev/null +++ b/packages/store/src/tables/HooksTable.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import { console } from "forge-std/console.sol"; +import { IStore } from "../IStore.sol"; +import { StoreSwitch } from "../StoreSwitch.sol"; +import { StoreCore } from "../StoreCore.sol"; +import { SchemaType } from "../Types.sol"; +import { Bytes } from "../Bytes.sol"; +import { Schema, SchemaLib } from "../Schema.sol"; +import { PackedCounter, PackedCounterLib } from "../PackedCounter.sol"; +import { AddressArray, AddressArray_ } from "../schemas/AddressArray.sol"; + +// -- User defined schema and tableId -- +bytes32 constant tableId = keccak256("mud.store.table.hooks"); + +// -- Autogenerated library to interact with tables with this schema -- +// TODO: autogenerate + +library HooksTable { + /** Get the table's schema */ + function getSchema() internal pure returns (Schema schema) { + return AddressArray_.getSchema(); + } + + /** Register the table's schema */ + function registerSchema() internal { + AddressArray_.registerSchema(tableId); + } + + function registerSchema(IStore store) internal { + AddressArray_.registerSchema(tableId, store); + } + + /** Set the table's data */ + function set(bytes32 key, address[] memory addresses) internal { + AddressArray_.set(tableId, key, addresses); + } + + /** + * Push an element to the addresses array + */ + function push(bytes32 key, address callback) internal { + AddressArray_.push(tableId, key, callback); + } + + /** Get the table's data */ + function get(bytes32 key) internal view returns (address[] memory addresses) { + return AddressArray_.get(tableId, key); + } + + function get(IStore store, bytes32 key) internal view returns (address[] memory addresses) { + return AddressArray_.get(tableId, store, key); + } +} diff --git a/packages/store/src/tables/MixedTable.sol b/packages/store/src/tables/MixedTable.sol new file mode 100644 index 0000000000..a420b2893b --- /dev/null +++ b/packages/store/src/tables/MixedTable.sol @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import { console } from "forge-std/console.sol"; +import { IStore } from "../IStore.sol"; +import { StoreSwitch } from "../StoreSwitch.sol"; +import { StoreCore } from "../StoreCore.sol"; +import { SchemaType } from "../Types.sol"; +import { Bytes } from "../Bytes.sol"; +import { Schema, SchemaLib } from "../Schema.sol"; +import { PackedCounter, PackedCounterLib } from "../PackedCounter.sol"; +import { Mixed, Mixed_ } from "../schemas/Mixed.sol"; + +// -- User defined tableId -- + +bytes32 constant tableId = keccak256("mud.store.table.mixed"); + +// -- Autogenerated library -- +// TODO: autogenerate + +library MixedTable { + /** Get the table's schema */ + function getSchema() internal pure returns (Schema) { + return Mixed_.getSchema(); + } + + /** Register the table's schema */ + function registerSchema() internal { + Mixed_.registerSchema(tableId); + } + + function registerSchema(IStore store) internal { + Mixed_.registerSchema(tableId, store); + } + + /** Set the table's data */ + function set( + bytes32 key, + uint32 u32, + uint128 u128, + uint32[] memory a32, + string memory s + ) internal { + Mixed_.set(tableId, key, u32, u128, a32, s); + } + + function set(bytes32 key, Mixed memory mixed) internal { + Mixed_.set(tableId, key, mixed.u32, mixed.u128, mixed.a32, mixed.s); + } + + function setU32(bytes32 key, uint32 u32) internal { + Mixed_.setU32(tableId, key, u32); + } + + function setU128(bytes32 key, uint128 u128) internal { + Mixed_.setU128(tableId, key, u128); + } + + function setA32(bytes32 key, uint32[] memory a32) internal { + Mixed_.setA32(tableId, key, a32); + } + + function setS(bytes32 key, string memory s) internal { + Mixed_.setS(tableId, key, s); + } + + /** Get the table's data */ + function get(bytes32 key) internal view returns (Mixed memory mixed) { + return Mixed_.get(tableId, key); + } + + function get(IStore store, bytes32 key) internal view returns (Mixed memory mixed) { + return Mixed_.get(tableId, store, key); + } +} diff --git a/packages/store/src/tables/RouteTable.sol b/packages/store/src/tables/RouteTable.sol new file mode 100644 index 0000000000..39c79dda30 --- /dev/null +++ b/packages/store/src/tables/RouteTable.sol @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import { console } from "forge-std/console.sol"; +import { IStore } from "../IStore.sol"; +import { StoreSwitch } from "../StoreSwitch.sol"; +import { StoreCore } from "../StoreCore.sol"; +import { SchemaType } from "../Types.sol"; +import { Bytes } from "../Bytes.sol"; +import { Schema, SchemaLib } from "../Schema.sol"; +import { Route, Route_ } from "../schemas/Route.sol"; + +// -- User defined tableId -- + +bytes32 constant tableId = keccak256("mud.store.table.route"); + +// -- Autogenerated library -- +// TODO: autogenerate + +library RouteTable { + /** Get the table's schema */ + function getSchema() internal pure returns (Schema schema) { + return Route_.getSchema(); + } + + /** Register the table's schema */ + function registerSchema() internal { + Route_.registerSchema(tableId); + } + + function registerSchema(IStore store) internal { + Route_.registerSchema(tableId, store); + } + + /** Set the table's data */ + function set( + bytes32 key, + address addr, + bytes4 selector, + uint8 executionMode + ) internal { + Route_.set(tableId, key, addr, selector, executionMode); + } + + function set(bytes32 key, Route memory data) internal { + Route_.set(tableId, key, data); + } + + function setAddress(bytes32 key, address addr) internal { + Route_.setAddress(tableId, key, addr); + } + + function setSelector(bytes32 key, bytes4 selector) internal { + Route_.setSelector(tableId, key, selector); + } + + function setExecutionMode(bytes32 key, uint8 executionMode) internal { + Route_.setExecutionMode(tableId, key, executionMode); + } + + /** Get the table's data */ + function get(bytes32 key) internal view returns (Route memory data) { + return Route_.get(tableId, key); + } + + function get(IStore store, bytes32 key) internal view returns (Route memory data) { + return Route_.get(tableId, store, key); + } +} diff --git a/packages/store/src/tables/Vector2Table.sol b/packages/store/src/tables/Vector2Table.sol new file mode 100644 index 0000000000..15fcdf7c24 --- /dev/null +++ b/packages/store/src/tables/Vector2Table.sol @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import { console } from "forge-std/console.sol"; +import { IStore } from "../IStore.sol"; +import { StoreSwitch } from "../StoreSwitch.sol"; +import { StoreCore } from "../StoreCore.sol"; +import { SchemaType } from "../Types.sol"; +import { Bytes } from "../Bytes.sol"; +import { Schema, SchemaLib } from "../Schema.sol"; +import { Vector2, Vector2_ } from "../schemas/Vector2.sol"; + +// -- User defined tableId -- + +bytes32 constant tableId = keccak256("mud.store.table.vector2"); + +// -- Autogenerated library -- +// TODO: autogenerate + +library Vector2Table { + /** Get the table's schema */ + function getSchema() internal pure returns (Schema schema) { + return Vector2_.getSchema(); + } + + /** Register the table's schema */ + function registerSchema() internal { + Vector2_.registerSchema(tableId); + } + + function registerSchema(IStore store) internal { + Vector2_.registerSchema(tableId, store); + } + + /** Set the table's data */ + function set( + bytes32 key, + uint32 x, + uint32 y + ) internal { + Vector2_.set(tableId, key, x, y); + } + + function set(bytes32 key, Vector2 memory vec2) internal { + Vector2_.set(tableId, key, vec2); + } + + function setX(bytes32 key, uint32 x) internal { + Vector2_.setX(tableId, key, x); + } + + function setY(bytes32 key, uint32 y) internal { + Vector2_.setY(tableId, key, y); + } + + /** Get the table's data */ + function get(bytes32 key) internal view returns (Vector2 memory vec2) { + return Vector2_.get(tableId, key); + } + + function get(IStore store, bytes32 key) internal view returns (Vector2 memory vec2) { + return Vector2_.get(tableId, store, key); + } + + function decode(bytes memory blob) internal pure returns (Vector2 memory vec2) { + return Vector2({ x: uint32(Bytes.slice4(blob, 0)), y: uint32(Bytes.slice4(blob, 4)) }); + } +} diff --git a/packages/store/tasks/compile.ts b/packages/store/tasks/compile.ts new file mode 100644 index 0000000000..65335021b4 --- /dev/null +++ b/packages/store/tasks/compile.ts @@ -0,0 +1,38 @@ +import { TASK_COMPILE_SOLIDITY } from "hardhat/builtin-tasks/task-names"; +import * as fs from "fs"; +import * as path from "path"; +import { subtask } from "hardhat/config"; + +subtask(TASK_COMPILE_SOLIDITY).setAction(async (_: { force: boolean; quiet: boolean }, { config }, runSuper) => { + console.log("Symlinking forge-style libraries"); + const symlinks: string[] = []; + const remappings = fs + .readFileSync("remappings.txt") + .toString() + .split("\n") + .filter((r) => r.length > 0) + .map((r) => r.split("=")); + + console.log("remappings", remappings); + for (const [library, libraryPath] of remappings) { + const symlinkPath = path.join(process.cwd(), library.replace("/", "")); + console.log("Adding symlink at path: " + symlinkPath); + if (fs.existsSync(symlinkPath)) { + console.warn("symlink already exists!"); + } else { + const libPath = path.join(config.paths.sources, "..", libraryPath); + fs.symlinkSync(libPath, symlinkPath, "dir"); + } + symlinks.push(symlinkPath); + } + try { + await runSuper(); + } catch (e) { + console.error(e); + } finally { + for (const symlink of symlinks) { + console.log("Removing symlink at path: " + symlink); + fs.unlinkSync(symlink); + } + } +}); diff --git a/packages/store/test/Buffer.t.sol b/packages/store/test/Buffer.t.sol new file mode 100644 index 0000000000..e081a61480 --- /dev/null +++ b/packages/store/test/Buffer.t.sol @@ -0,0 +1,222 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import "forge-std/Test.sol"; +import { Cast } from "../src/Cast.sol"; +import "../src/Buffer.sol"; + +contract BufferTest is Test { + function testAllocateBuffer() public { + // !gasreport allocate a buffer + Buffer buf = Buffer_.allocate(32); + + // !gasreport get buffer length + buf.length(); + + // !gasreport get buffer pointer + buf.ptr(); + + // !gasreport get buffer capacity + buf.capacity(); + + assertEq(uint256(buf.length()), 0); + assertEq(uint256(buf.capacity()), 32); + } + + function testFromBytes() public { + bytes memory data = abi.encodePacked(bytes8(0x0102030405060708)); + + // !gasreport create a buffer from 8 bytes + Buffer buf = Buffer_.fromBytes(data); + + assertEq(uint256(buf.length()), 8); + assertEq(uint256(buf.capacity()), 8); + assertEq(keccak256(buf.toBytes()), keccak256(data)); + } + + function testFromBytesFuzzy(bytes memory data) public { + Buffer buf = Buffer_.fromBytes(data); + assertEq(uint256(buf.length()), data.length); + assertEq(uint256(buf.capacity()), data.length); + assertEq(keccak256(buf.toBytes()), keccak256(data)); + } + + function testSetLength() public { + Buffer buf = Buffer_.allocate(32); + + // !gasreport set buffer length unchecked + buf._setLengthUnchecked(8); + + // !gasreport set buffer length + buf._setLength(16); + + assertEq(uint256(buf.length()), 16); + assertEq(uint256(buf.capacity()), 32); + } + + function testSetLengthFuzzy(bytes memory data, uint16 length) public { + Buffer buf = Buffer_.fromBytes(data); + assertEq(uint256(buf.capacity()), data.length); + buf._setLengthUnchecked(length); + assertEq(uint256(buf.length()), length); + } + + function testFailSetLength() public pure { + Buffer buf = Buffer_.allocate(32); + buf._setLength(33); + } + + function testAppend() public { + Buffer buf = Buffer_.allocate(32); + bytes memory data1 = abi.encodePacked(bytes8(0x0102030405060708)); + bytes memory data2 = abi.encodePacked(bytes8(0x090a0b0c0d0e0f10)); + + // !gasreport append unchecked bytes memory (8) to buffer + buf.appendUnchecked(data1); + + // !gasreport append bytes memory (8) to buffer + buf.append(data2); + + assertEq(uint256(buf.length()), 16); + assertEq(buf.read8(0), bytes8(0x0102030405060708)); + assertEq(buf.read8(8), bytes8(0x090a0b0c0d0e0f10)); + } + + function testAppendFuzzy( + bytes memory input, + bytes memory append1, + bytes memory append2 + ) public { + Buffer buffer = Buffer_.allocate(uint128(input.length + append1.length + append2.length)); + buffer.append(input); + buffer.append(append1); + buffer.append(append2); + assertEq(keccak256(buffer.toBytes()), keccak256(bytes.concat(input, append1, append2))); + } + + function testCompareGasToConcat() public { + bytes memory data1 = abi.encodePacked(keccak256("data1")); + bytes memory data2 = abi.encodePacked(keccak256("data2")); + bytes memory data3 = abi.encodePacked(keccak256("data3")); + + // !gasreport concat 3 bytes memory (32) using buffer + Buffer buf = Buffer_.concat(data1, data2, data3); + + // !gasreport concat 3 bytes memory (32) using bytes.concat + bytes memory concat = bytes.concat(data1, data2, data3); + + // !gasreport concat 3 bytes memory (32) using abi.encodePacked + bytes memory concat2 = abi.encodePacked(data1, data2, data3); + + assertEq(keccak256(buf.toBytes()), keccak256(concat)); + assertEq(keccak256(buf.toBytes()), keccak256(concat2)); + } + + function testAppendFixed() public { + Buffer buf = Buffer_.allocate(32); + bytes32 data1 = bytes32(bytes8(0x0102030405060708)); + bytes32 data2 = bytes32(bytes8(0x090a0b0c0d0e0f10)); + + // !gasreport append unchecked bytes8 of bytes32 to buffer + buf.appendUnchecked(data1, 8); + + // !gasreport append bytes8 of bytes32 to buffer + buf.append(data2, 8); + + assertEq(uint256(buf.length()), 16); + assertEq(buf.read8(0), bytes8(0x0102030405060708)); + assertEq(buf.read8(8), bytes8(0x090a0b0c0d0e0f10)); + } + + function testToBytes() public { + Buffer buf = Buffer_.allocate(32); + bytes memory data1 = abi.encodePacked(bytes8(0x0102030405060708)); + bytes memory data2 = abi.encodePacked(bytes8(0x090a0b0c0d0e0f10)); + bytes memory data = abi.encodePacked(data1, data2); + + buf.append(data1); + buf.append(data2); + + // !gasreport buffer (32 bytes) to bytes memory + bytes memory bufferData = buf.toBytes(); + + assertEq(keccak256(bufferData), keccak256(data)); + } + + function testRead() public { + Buffer buf = Buffer_.allocate(32); + bytes memory data = abi.encodePacked(bytes8(0x0102030405060708)); + buf.append(data); + + // !gasreport read bytes32 from buffer + bytes32 value = buf.read32(4); + + assertEq(value, bytes32(bytes4(0x05060708))); + + // !gasreport read bytes8 with offset 3 from buffer + bytes8 value2 = buf.read8(3); + + assertEq(value2, bytes8(bytes5(0x0405060708))); + + // !gasreport read bytes1 with offset 7 from buffer + bytes1 value3 = buf.read1(7); + + assertEq(value3, bytes1(0x08)); + } + + function testToArrayUint32() public { + Buffer buf = Buffer_.allocate(32); + bytes memory data1 = abi.encodePacked(bytes8(0x0102030405060708)); + buf.append(data1); + + // !gasreport buffer toArray with element length 4 + uint256 arrayPtr = buf.toArray(4); + + // !gasreport convert array pointer to uint32[] + uint32[] memory arr = Cast.toUint32Array(arrayPtr); + + assertEq(arr.length, 2); + assertEq(arr[0], 0x01020304); + assertEq(arr[1], 0x05060708); + } + + function testToArrayUint256() public { + Buffer buf = Buffer_.allocate(8); + bytes memory data = abi.encodePacked(bytes8(0x0102030405060708)); + buf.append(data); + + uint256 arrayPtr = buf.toArray(4); + + // !gasreport convert array pointer to uint256[] + uint256[] memory arr = Cast.toUint256Array(arrayPtr); + + assertEq(arr.length, 2); + assertEq(arr[0], 0x01020304); + assertEq(arr[1], 0x05060708); + } + + function testToArrayUint256TrailingData() public { + Buffer buf = Buffer_.allocate(10); + bytes memory data = abi.encodePacked(bytes8(0x0102030405060708), bytes2(0x090a)); + buf.append(data); + uint256 arrayPtr = buf.toArray(4); + uint256[] memory arr = Cast.toUint256Array(arrayPtr); + + // The trailing bytes2 data is ignored because it doesn't align with one `elementSize` + assertEq(arr.length, 2); + assertEq(arr[0], 0x01020304); + assertEq(arr[1], 0x05060708); + } + + function testSlice() public { + Buffer buf = Buffer_.allocate(32); + bytes memory data = abi.encodePacked(bytes8(0x0102030405060708)); + buf.append(data); + + // !gasreport slice 4 bytes from buffer with offset 4 + bytes memory slice = buf.slice(4, 4); + + assertEq(uint256(slice.length), 4); + assertEq(keccak256(slice), keccak256(abi.encodePacked(bytes4(0x05060708)))); + } +} diff --git a/packages/store/test/Bytes.t.sol b/packages/store/test/Bytes.t.sol new file mode 100644 index 0000000000..9ae548a3d9 --- /dev/null +++ b/packages/store/test/Bytes.t.sol @@ -0,0 +1,272 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import "forge-std/Test.sol"; +import { Bytes } from "../src/Bytes.sol"; + +contract BytesTest is Test { + function testFromBytesArray() public { + bytes[] memory input = new bytes[](2); + input[0] = new bytes(32); + input[0][0] = 0x01; + input[0][31] = 0x02; + input[1] = new bytes(32); + input[1][0] = 0x03; + input[1][31] = 0x04; + + // !gasreport create bytes from bytes array + bytes memory output = Bytes.from(input); + + assertEq(output.length, 64); + assertEq(uint256(Bytes.toBytes32(output, 0)), 0x0100000000000000000000000000000000000000000000000000000000000002); + assertEq(uint256(Bytes.toBytes32(output, 32)), 0x0300000000000000000000000000000000000000000000000000000000000004); + } + + function testFromUint8Array() public { + uint8[] memory input = new uint8[](2); + input[0] = 0x01; + input[1] = 0x02; + + // !gasreport create bytes from uint8 array + bytes memory output = Bytes.from(input); + + assertEq(output.length, 2); + assertEq(uint256(uint8(output[0])), 0x01); + assertEq(uint256(uint8(output[1])), 0x02); + } + + function testFromUint16Array() public { + uint16[] memory input = new uint16[](3); + input[0] = 0x0102; + input[1] = 0x0304; + input[2] = 0x0506; + + // !gasreport create bytes from uint16 array + bytes memory output = Bytes.from(input); + + assertEq(output.length, 6); + assertEq(uint256(uint8(output[0])), 0x01); + assertEq(uint256(uint8(output[1])), 0x02); + assertEq(uint256(uint8(output[2])), 0x03); + assertEq(uint256(uint8(output[3])), 0x04); + assertEq(uint256(uint8(output[4])), 0x05); + assertEq(uint256(uint8(output[5])), 0x06); + } + + function testFromUint32Array() public { + uint32[] memory input = new uint32[](2); + input[0] = 0x01020304; + input[1] = 0x05060708; + + // !gasreport create bytes from uint32 array + bytes memory output = Bytes.from(input); + + assertEq(output.length, 8); + assertEq(uint256(uint8(output[0])), 0x01); + assertEq(uint256(uint8(output[1])), 0x02); + assertEq(uint256(uint8(output[2])), 0x03); + assertEq(uint256(uint8(output[3])), 0x04); + assertEq(uint256(uint8(output[4])), 0x05); + assertEq(uint256(uint8(output[5])), 0x06); + assertEq(uint256(uint8(output[6])), 0x07); + assertEq(uint256(uint8(output[7])), 0x08); + } + + function testToBytes32() public { + bytes memory input = new bytes(32); + input[0] = 0x01; + input[31] = 0x02; + + // !gasreport create bytes32 from bytes memory with offset 0 + bytes32 output = Bytes.toBytes32(input, 0); + + assertEq(uint256(output), 0x0100000000000000000000000000000000000000000000000000000000000002); + } + + function testToBytes32CrossWord() public { + bytes memory input = new bytes(64); + input[0 + 16] = 0x01; + input[31 + 16] = 0x02; + + // !gasreport create bytes32 from bytes memory with offset 16 + bytes32 output = Bytes.toBytes32(input, 16); + + assertEq(uint256(output), 0x0100000000000000000000000000000000000000000000000000000000000002); + } + + function testToBytes32Array() public { + bytes memory input = new bytes(64); + input[0] = 0x01; + input[31] = 0x02; + input[32] = 0x03; + input[63] = 0x04; + + // !gasreport create bytes32 array from bytes memory + bytes32[] memory output = Bytes.toBytes32Array(input); + + assertEq(output.length, 2); + assertEq(uint256(output[0]), 0x0100000000000000000000000000000000000000000000000000000000000002); + assertEq(uint256(output[1]), 0x0300000000000000000000000000000000000000000000000000000000000004); + } + + function testFromAndToUint32Array() public { + uint32[] memory input = new uint32[](2); + input[0] = 0x01020304; + input[1] = 0x05060708; + + bytes memory tight = Bytes.from(input); + assertEq(tight.length, 8); + + // !gasreport create uint32 array from bytes memory + uint32[] memory output = Bytes.toUint32Array(tight); + + assertEq(output.length, 2); + assertEq(output[0], 0x01020304); + assertEq(output[1], 0x05060708); + } + + function testToAndFromBytes24Array() public { + bytes24[] memory input = new bytes24[](2); + input[0] = bytes24(0x0102030405060708090a0b0c0d0e0f101112131415161718); + input[1] = bytes24(0x19202122232425262728292a2b2c2d2e2f30313233343536); + + // !gasreport tightly pack bytes24 array into bytes array + bytes memory tight = Bytes.from(input); + + assertEq(tight.length, 48); + + // !gasreport create uint32 array from bytes memory + bytes24[] memory output = Bytes.toBytes24Array(tight); + + assertEq(output.length, 2); + assertEq(output[0], input[0]); + assertEq(output[1], input[1]); + } + + function testToBytes32ArrayUneven() public { + bytes memory input = new bytes(65); + input[0] = 0x01; + input[31] = 0x02; + input[32] = 0x03; + input[63] = 0x04; + input[64] = 0x05; + + // !gasreport create bytes32 array from bytes memory with uneven length + bytes32[] memory output = Bytes.toBytes32Array(input); + + assertEq(output.length, 3); + assertEq(uint256(output[0]), 0x0100000000000000000000000000000000000000000000000000000000000002); + assertEq(uint256(output[1]), 0x0300000000000000000000000000000000000000000000000000000000000004); + assertEq(uint256(output[2]), 0x0500000000000000000000000000000000000000000000000000000000000000); + } + + function testEquals() public { + bytes memory a = bytes("a"); + bytes memory b = bytes("a"); + + // !gasreport compare equal bytes + bool equals = Bytes.equals(a, b); + + assertTrue(equals); + } + + function testEqualsFalse() public { + bytes memory a = bytes("a"); + bytes memory b = bytes("b"); + + // !gasreport compare unequal bytes + bool equals = Bytes.equals(a, b); + + assertFalse(equals); + } + + function testEqualsFalseDiffLength() public { + bytes memory a = bytes("a"); + bytes memory b = bytes("aa"); + assertFalse(Bytes.equals(a, b)); + } + + function testSlice() public { + bytes memory a = new bytes(5); + a[0] = 0x01; + a[1] = 0x02; + a[2] = 0x03; + a[3] = 0x04; + a[4] = 0x05; + + // !gasreport slice bytes (with copying) with offset 1 and length 3 + bytes memory b = Bytes.slice(a, 1, 3); + + assertEq(b.length, 3); + assertEq(uint256(uint8(b[0])), 0x02); + assertEq(uint256(uint8(b[1])), 0x03); + assertEq(uint256(uint8(b[2])), 0x04); + } + + // TODO: add tests for other sliceX functions + function testSlice3() public { + bytes memory a = new bytes(5); + a[0] = 0x01; + a[1] = 0x02; + a[2] = 0x03; + a[3] = 0x04; + a[4] = 0x05; + + // !gasreport slice bytes3 with offset 1 + bytes3 b = Bytes.slice3(a, 1); + + assertEq(b.length, 3); + assertEq(uint256(uint8(b[0])), 0x02); + assertEq(uint256(uint8(b[1])), 0x03); + assertEq(uint256(uint8(b[2])), 0x04); + } + + function testSlice32() public { + bytes32 original = keccak256("some data"); + bytes memory input = abi.encodePacked(bytes10(keccak256("irrelevant data")), original); + + // !gasreport slice bytes32 with offset 10 + bytes32 output = Bytes.slice32(input, 10); + + assertEq(output, original); + } + + function testSetBytes1() public { + bytes32 input = bytes32(0); + + // !gasreport set bytes1 in bytes32 + Bytes.setBytes1(input, 8, 0xff); + + assertEq(Bytes.setBytes1(input, 0, 0x01), bytes32(bytes1(0x01))); + assertEq(Bytes.setBytes1(input, 31, 0x01), bytes32(uint256(0x01))); + } + + function testSetBytes2() public { + bytes32 input = bytes32(0); + + // !gasreport set bytes2 in bytes32 + Bytes.setBytes2(input, 8, 0xffff); + + assertEq(Bytes.setBytes2(input, 0, 0xffff), bytes32(bytes2(0xffff))); + assertEq(Bytes.setBytes2(input, 30, 0xffff), bytes32(uint256(0xffff))); + } + + function testSetBytes4() public { + bytes32 input = bytes32(0); + + // !gasreport set bytes4 in bytes32 + Bytes.setBytes4(input, 8, 0xffffffff); + + assertEq(Bytes.setBytes4(input, 0, 0xffffffff), bytes32(bytes4(0xffffffff))); + assertEq(Bytes.setBytes4(input, 30, 0xffffffff), bytes32(uint256(0xffff))); + assertEq(Bytes.setBytes4(input, 28, 0xffffffff), bytes32(uint256(0xffffffff))); + + bytes32 input2 = bytes32(0x0000000a000a0000000000000000000000000000000000000000000000000000); + bytes4 overwrite = bytes4(0x0000006d); + + assertEq( + Bytes.setBytes4(input2, 0, overwrite), + bytes32(0x0000006d000a0000000000000000000000000000000000000000000000000000) + ); + } +} diff --git a/packages/store/test/Gas.t.sol b/packages/store/test/Gas.t.sol new file mode 100644 index 0000000000..9d2017cb28 --- /dev/null +++ b/packages/store/test/Gas.t.sol @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import "forge-std/Test.sol"; +import { Bytes } from "../src/Bytes.sol"; +import { Buffer_ } from "../src/Buffer.sol"; + +struct Mixed { + uint32 u32; + uint128 u128; + uint32[] a32; + string s; +} + +contract SomeContract { + function doSomethingWithBytes(bytes memory data) public {} +} + +contract GasTest is Test { + SomeContract someContract = new SomeContract(); + + function testCompareAbiEncodeVsCustom() public { + Mixed memory mixed = Mixed({ u32: 1, u128: 2, a32: new uint32[](3), s: "hello" }); + mixed.a32[0] = 1; + mixed.a32[1] = 2; + mixed.a32[2] = 3; + + // !gasreport abi encode + bytes memory abiEncoded = abi.encode(mixed); + + // !gasreport abi decode + Mixed memory abiDecoded = abi.decode(abiEncoded, (Mixed)); + + // !gasreport custom encode + bytes memory customEncoded = customEncode(mixed); + + // !gasreport custom decode + Mixed memory customDecoded = customDecode(customEncoded); + + console.log("Length comparison: abi encode %s, custom %s", abiEncoded.length, customEncoded.length); + + // !gasreport pass abi encoded bytes to external contract + someContract.doSomethingWithBytes(abiEncoded); + + // !gasreport pass custom encoded bytes to external contract + someContract.doSomethingWithBytes(customEncoded); + + assertEq(keccak256(abi.encode(abiDecoded)), keccak256(abi.encode(customDecoded))); + } +} + +function customEncode(Mixed memory mixed) pure returns (bytes memory) { + return abi.encodePacked(mixed.u32, mixed.u128, Bytes.from(mixed.a32), mixed.s); +} + +function customDecode(bytes memory input) view returns (Mixed memory) { + console.log(input.length); + + return + Mixed({ + u32: uint32(Bytes.slice4(input, 0)), + u128: uint128(Bytes.slice16(input, 4)), + a32: Bytes.toUint32Array(Bytes.slice(input, 20, 3 * 4)), + s: string(Bytes.slice(input, 20 + 3 * 4, input.length - 20 - 3 * 4)) + }); +} diff --git a/packages/store/test/MixedTable.t.sol b/packages/store/test/MixedTable.t.sol new file mode 100644 index 0000000000..68565d18bc --- /dev/null +++ b/packages/store/test/MixedTable.t.sol @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import "forge-std/Test.sol"; +import { MixedTable, tableId as MixedTableId, Mixed } from "../src/tables/MixedTable.sol"; +import { StoreCore } from "../src/StoreCore.sol"; +import { SchemaType } from "../src/Types.sol"; +import { StoreView } from "../src/StoreView.sol"; +import { Schema } from "../src/Schema.sol"; + +contract MixedTableTest is Test, StoreView { + Mixed private testMixed; + + function testRegisterAndGetSchema() public { + // !gasreport register MixedTable schema + MixedTable.registerSchema(); + + Schema registeredSchema = StoreCore.getSchema(MixedTableId); + Schema declaredSchema = MixedTable.getSchema(); + + assertEq(keccak256(abi.encode(registeredSchema)), keccak256(abi.encode(declaredSchema))); + } + + function testSetAndGet() public { + MixedTable.registerSchema(); + bytes32 key = keccak256("somekey"); + + uint32[] memory a32 = new uint32[](2); + a32[0] = 3; + a32[1] = 4; + string memory s = "some string"; + + // !gasreport set record in MixedTable + MixedTable.set({ key: key, u32: 1, u128: 2, a32: a32, s: s }); + + // !gasreport get record from MixedTable + Mixed memory mixed = MixedTable.get(key); + + assertEq(mixed.u32, 1); + assertEq(mixed.u128, 2); + assertEq(mixed.a32[0], 3); + assertEq(mixed.a32[1], 4); + assertEq(mixed.s, s); + } + + function testCompareSolidity() public { + Mixed memory mixed = Mixed({ u32: 1, u128: 2, a32: new uint32[](2), s: "some string" }); + mixed.a32[0] = 3; + mixed.a32[1] = 4; + + // !gasreport store Mixed struct in storage (native solidity) + testMixed = mixed; + } +} diff --git a/packages/store/test/PackedCounter.t.sol b/packages/store/test/PackedCounter.t.sol new file mode 100644 index 0000000000..8ec1938f73 --- /dev/null +++ b/packages/store/test/PackedCounter.t.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import "forge-std/Test.sol"; +import { PackedCounter, PackedCounterLib } from "../src/PackedCounter.sol"; + +contract PackedCounterTest is Test { + function testTotal() public { + uint16[] memory counters = new uint16[](4); + counters[0] = 1; + counters[1] = 2; + counters[2] = 3; + counters[3] = 4; + + // !gasreport pack uint16 array into PackedCounter + PackedCounter packedCounter = PackedCounterLib.pack(counters); + + // !gasreport get total of PackedCounter + packedCounter.total(); + + assertEq(packedCounter.total(), 10); + } + + function testAtIndex() public { + uint16[] memory counters = new uint16[](4); + counters[0] = 1; + counters[1] = 2; + counters[2] = 3; + counters[3] = 4; + + PackedCounter packedCounter = PackedCounterLib.pack(counters); + + // !gasreport get value at index of PackedCounter + packedCounter.atIndex(3); + + assertEq(packedCounter.atIndex(0), 1); + assertEq(packedCounter.atIndex(1), 2); + assertEq(packedCounter.atIndex(2), 3); + assertEq(packedCounter.atIndex(3), 4); + } + + function testSetAtIndex() public { + uint16[] memory counters = new uint16[](4); + counters[0] = 1; + counters[1] = 2; + counters[2] = 3; + counters[3] = 4; + + PackedCounter packedCounter = PackedCounterLib.pack(counters); + + // !gasreport set value at index of PackedCounter + packedCounter = packedCounter.setAtIndex(2, 5); + + assertEq(packedCounter.atIndex(0), 1); + assertEq(packedCounter.atIndex(1), 2); + assertEq(packedCounter.atIndex(2), 5); + assertEq(packedCounter.atIndex(3), 4); + assertEq(packedCounter.total(), 12); + } +} diff --git a/packages/store/test/RouteTable.t.sol b/packages/store/test/RouteTable.t.sol new file mode 100644 index 0000000000..e7362666d4 --- /dev/null +++ b/packages/store/test/RouteTable.t.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import "forge-std/Test.sol"; +import { RouteTable, tableId as RouteTableId, Route } from "../src/tables/RouteTable.sol"; +import { StoreCore } from "../src/StoreCore.sol"; +import { SchemaType } from "../src/Types.sol"; +import { StoreView } from "../src/StoreView.sol"; +import { Schema } from "../src/Schema.sol"; + +contract RouteTableTest is Test, StoreView { + function testRegisterAndGetSchema() public { + // !gasreport register RouteTable schema + RouteTable.registerSchema(); + + Schema registeredSchema = StoreCore.getSchema(RouteTableId); + Schema declaredSchema = RouteTable.getSchema(); + + assertEq(keccak256(abi.encode(registeredSchema)), keccak256(abi.encode(declaredSchema))); + } + + function testSetAndGet() public { + RouteTable.registerSchema(); + bytes32 key = keccak256("somekey"); + + address addr = address(0x1234); + bytes4 selector = bytes4(0x12345678); + uint8 executionMode = 1; + + // !gasreport set RouteTable record + RouteTable.set(key, addr, selector, executionMode); + + // !gasreport get RouteTable record + Route memory systemEntry = RouteTable.get(key); + + assertEq(systemEntry.addr, addr); + assertEq(systemEntry.selector, selector); + assertEq(systemEntry.executionMode, executionMode); + } +} diff --git a/packages/store/test/Schema.t.sol b/packages/store/test/Schema.t.sol new file mode 100644 index 0000000000..be6c59611d --- /dev/null +++ b/packages/store/test/Schema.t.sol @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import "forge-std/Test.sol"; +import { Schema, SchemaLib } from "../src/Schema.sol"; +import { SchemaType } from "../src/Types.sol"; + +contract SchemaTest is Test { + function testEncodeDecodeSchema() public { + uint256 gas = gasleft(); + Schema schema = SchemaLib.encode( + SchemaType.Uint8, // 1 byte + SchemaType.Uint16, // 2 bytes + SchemaType.Uint32, // 4 bytes + SchemaType.Uint128, // 16 bytes + SchemaType.Uint256, // 32 bytes + SchemaType.Uint32Array // 0 bytes (because it's dynamic) + ); + gas = gas - gasleft(); + console.log("GAS REPORT: encode schema with 6 entries [SchemaLib.encode]: %s", gas); + + // !gasreport get schema type at index + SchemaType schemaType1 = schema.atIndex(0); + + assertEq(uint8(schemaType1), uint8(SchemaType.Uint8)); + assertEq(uint8(schema.atIndex(1)), uint8(SchemaType.Uint16)); + assertEq(uint8(schema.atIndex(2)), uint8(SchemaType.Uint32)); + assertEq(uint8(schema.atIndex(3)), uint8(SchemaType.Uint128)); + assertEq(uint8(schema.atIndex(4)), uint8(SchemaType.Uint256)); + assertEq(uint8(schema.atIndex(5)), uint8(SchemaType.Uint32Array)); + } + + function testFailInvalidSchemaStaticAfterDynamic() public pure { + SchemaLib.encode(SchemaType.Uint8, SchemaType.Uint32Array, SchemaType.Uint16); + } + + function testEncodeMaxValidLength() public { + SchemaType[] memory schema = new SchemaType[](28); + schema[0] = SchemaType.Uint256; + schema[1] = SchemaType.Uint256; + schema[2] = SchemaType.Uint256; + schema[3] = SchemaType.Uint256; + schema[4] = SchemaType.Uint256; + schema[5] = SchemaType.Uint256; + schema[6] = SchemaType.Uint256; + schema[7] = SchemaType.Uint256; + schema[8] = SchemaType.Uint256; + schema[9] = SchemaType.Uint256; + schema[10] = SchemaType.Uint256; + schema[11] = SchemaType.Uint256; + schema[12] = SchemaType.Uint256; + schema[13] = SchemaType.Uint256; + schema[14] = SchemaType.Uint32Array; + schema[15] = SchemaType.Uint32Array; + schema[16] = SchemaType.Uint32Array; + schema[17] = SchemaType.Uint32Array; + schema[18] = SchemaType.Uint32Array; + schema[19] = SchemaType.Uint32Array; + schema[20] = SchemaType.Uint32Array; + schema[21] = SchemaType.Uint32Array; + schema[22] = SchemaType.Uint32Array; + schema[23] = SchemaType.Uint32Array; + schema[24] = SchemaType.Uint32Array; + schema[25] = SchemaType.Uint32Array; + schema[26] = SchemaType.Uint32Array; + schema[27] = SchemaType.Uint32Array; + Schema encodedSchema = SchemaLib.encode(schema); + + assertEq(encodedSchema.numStaticFields() + encodedSchema.numDynamicFields(), 28); + } + + function testFailEncodeTooLong() public pure { + SchemaType[] memory schema = new SchemaType[](29); + schema[0] = SchemaType.Uint256; + schema[1] = SchemaType.Uint256; + schema[2] = SchemaType.Uint256; + schema[3] = SchemaType.Uint256; + schema[4] = SchemaType.Uint256; + schema[5] = SchemaType.Uint256; + schema[6] = SchemaType.Uint256; + schema[7] = SchemaType.Uint256; + schema[8] = SchemaType.Uint256; + schema[9] = SchemaType.Uint256; + schema[10] = SchemaType.Uint256; + schema[11] = SchemaType.Uint256; + schema[12] = SchemaType.Uint256; + schema[13] = SchemaType.Uint256; + schema[14] = SchemaType.Uint256; + schema[15] = SchemaType.Uint256; + schema[16] = SchemaType.Uint256; + schema[17] = SchemaType.Uint32Array; + schema[18] = SchemaType.Uint32Array; + schema[19] = SchemaType.Uint32Array; + schema[20] = SchemaType.Uint32Array; + schema[21] = SchemaType.Uint32Array; + schema[22] = SchemaType.Uint32Array; + schema[23] = SchemaType.Uint32Array; + schema[24] = SchemaType.Uint32Array; + schema[25] = SchemaType.Uint32Array; + schema[26] = SchemaType.Uint32Array; + schema[27] = SchemaType.Uint32Array; + schema[28] = SchemaType.Uint32Array; + SchemaLib.encode(schema); + } + + function testEncodeMaxValidDynamic() public { + SchemaType[] memory schema = new SchemaType[](14); + schema[0] = SchemaType.Uint32Array; + schema[1] = SchemaType.Uint32Array; + schema[2] = SchemaType.Uint32Array; + schema[3] = SchemaType.Uint32Array; + schema[4] = SchemaType.Uint32Array; + schema[5] = SchemaType.Uint32Array; + schema[6] = SchemaType.Uint32Array; + schema[7] = SchemaType.Uint32Array; + schema[8] = SchemaType.Uint32Array; + schema[9] = SchemaType.Uint32Array; + schema[10] = SchemaType.Uint32Array; + schema[11] = SchemaType.Uint32Array; + schema[12] = SchemaType.Uint32Array; + schema[13] = SchemaType.Uint32Array; + Schema encodedSchema = SchemaLib.encode(schema); + + assertEq(encodedSchema.numDynamicFields(), 14); + } + + function testFailEncodeTooManyDynamic() public pure { + SchemaType[] memory schema = new SchemaType[](15); + schema[0] = SchemaType.Uint32Array; + schema[1] = SchemaType.Uint32Array; + schema[2] = SchemaType.Uint32Array; + schema[3] = SchemaType.Uint32Array; + schema[4] = SchemaType.Uint32Array; + schema[5] = SchemaType.Uint32Array; + schema[6] = SchemaType.Uint32Array; + schema[7] = SchemaType.Uint32Array; + schema[8] = SchemaType.Uint32Array; + schema[9] = SchemaType.Uint32Array; + schema[10] = SchemaType.Uint32Array; + schema[11] = SchemaType.Uint32Array; + schema[12] = SchemaType.Uint32Array; + schema[13] = SchemaType.Uint32Array; + schema[14] = SchemaType.Uint32Array; + SchemaLib.encode(schema); + } + + function testGetStaticSchemaLength() public { + Schema schema = SchemaLib.encode( + SchemaType.Uint8, // 1 byte + SchemaType.Uint16, // 2 bytes + SchemaType.Uint32, // 4 bytes + SchemaType.Uint128, // 16 bytes + SchemaType.Uint256, // 32 bytes + SchemaType.Uint32Array // 0 bytes (because it's dynamic) + ); + + // !gasreport get static data length from schema + uint256 length = schema.staticDataLength(); + + assertEq(length, 55); + } + + function testGetNumStaticFields() public { + Schema schema = SchemaLib.encode( + SchemaType.Uint8, // 1 byte + SchemaType.Uint16, // 2 bytes + SchemaType.Uint32, // 4 bytes + SchemaType.Uint128, // 16 bytes + SchemaType.Uint256, // 32 bytes + SchemaType.Uint32Array // 0 bytes (because it's dynamic) + ); + + // !gasreport get number of static fields from schema + uint256 num = schema.numStaticFields(); + + assertEq(num, 5); + } + + function testGetNumDynamicFields() public { + Schema schema = SchemaLib.encode( + SchemaType.Uint8, // 1 byte + SchemaType.Uint16, // 2 bytes + SchemaType.Uint32, // 4 bytes + SchemaType.Uint128, // 16 bytes + SchemaType.Uint256, // 32 bytes + SchemaType.Uint32Array // 0 bytes (because it's dynamic) + ); + + // !gasreport get number of dynamic fields from schema + uint256 num = schema.numDynamicFields(); + + assertEq(num, 1); + } + + function testValidate() public view { + SchemaType[] memory schema = new SchemaType[](28); + schema[0] = SchemaType.Uint256; + schema[1] = SchemaType.Uint256; + schema[2] = SchemaType.Uint256; + schema[3] = SchemaType.Uint256; + schema[4] = SchemaType.Uint256; + schema[5] = SchemaType.Uint256; + schema[6] = SchemaType.Uint256; + schema[7] = SchemaType.Uint256; + schema[8] = SchemaType.Uint256; + schema[9] = SchemaType.Uint256; + schema[10] = SchemaType.Uint256; + schema[11] = SchemaType.Uint256; + schema[12] = SchemaType.Uint256; + schema[13] = SchemaType.Uint256; + schema[14] = SchemaType.Uint32Array; + schema[15] = SchemaType.Uint32Array; + schema[16] = SchemaType.Uint32Array; + schema[17] = SchemaType.Uint32Array; + schema[18] = SchemaType.Uint32Array; + schema[19] = SchemaType.Uint32Array; + schema[20] = SchemaType.Uint32Array; + schema[21] = SchemaType.Uint32Array; + schema[22] = SchemaType.Uint32Array; + schema[23] = SchemaType.Uint32Array; + schema[24] = SchemaType.Uint32Array; + schema[25] = SchemaType.Uint32Array; + schema[26] = SchemaType.Uint32Array; + schema[27] = SchemaType.Uint32Array; + Schema encodedSchema = SchemaLib.encode(schema); + + // !gasreport validate schema + encodedSchema.validate(); + } + + function testFailValidate() public view { + Schema.wrap(keccak256("some invalid schema")).validate(); + } + + function testIsEmptyTrue() public { + SchemaType[] memory schema = new SchemaType[](0); + Schema encodedSchema = SchemaLib.encode(schema); + + // !gasreport check if schema is empty (empty schema) + bool empty = encodedSchema.isEmpty(); + + assertTrue(empty); + } + + function testIsEmptyFalse() public { + Schema encodedSchema = SchemaLib.encode(SchemaType.Uint256); + + // !gasreport check if schema is empty (non-empty schema) + bool empty = encodedSchema.isEmpty(); + + assertFalse(empty); + } +} diff --git a/packages/store/test/Storage.t.sol b/packages/store/test/Storage.t.sol new file mode 100644 index 0000000000..199e1c8faa --- /dev/null +++ b/packages/store/test/Storage.t.sol @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import "forge-std/Test.sol"; +import { Cast } from "../src/Cast.sol"; +import { Storage } from "../src/Storage.sol"; +import { Utils } from "../src/Utils.sol"; +import { Bytes } from "../src/Bytes.sol"; + +contract StorageTest is Test { + function testStoreLoad() public { + bytes memory data1 = abi.encodePacked( + bytes1(0x01), + bytes32(0x0200000000000000000000000000000000000000000000000000000000000003), + bytes1(0x04) + ); + + bytes memory originalDataFirstSlot = abi.encodePacked( + bytes32(0x42000000000000000000000000000000000000000000000000000000000069FF) + ); + bytes memory originalDataLastSlot = abi.encodePacked( + bytes32(0xFF42000000000000000000000000000000000000000000000000000000000069) + ); + + uint256 storagePointer = uint256(keccak256("some location")); + uint256 storagePointerTwoSlotsAfter = storagePointer + 2; + + // First store some data to storage at the target slot and two slots after the target slot + + // !gasreport store 1 storage slot + Storage.store({ storagePointer: storagePointer, data: originalDataFirstSlot }); + + Storage.store({ storagePointer: storagePointerTwoSlotsAfter, data: originalDataLastSlot }); + + // Then set the target slot, partially overwriting the first and third slot, but using safeTrail and offset + + // !gasreport store 34 bytes over 3 storage slots (with offset and safeTrail)) + Storage.store({ storagePointer: storagePointer, offset: 31, data: data1 }); + + // Assert the first slot has the correct value + assertEq( + Storage.load({ storagePointer: storagePointer }), + bytes32(0x4200000000000000000000000000000000000000000000000000000000006901) + ); + + // Assert the second slot has the correct value + assertEq( + Storage.load({ storagePointer: storagePointer + 1 }), + bytes32(0x0200000000000000000000000000000000000000000000000000000000000003) + ); + + // Assert that the trailing slot has the correct value + assertEq( + Storage.load({ storagePointer: storagePointerTwoSlotsAfter }), + bytes32(0x0442000000000000000000000000000000000000000000000000000000000069) + ); + + // Assert we can load the correct partial value from storage + + // !gasreport load 34 bytes over 3 storage slots (with offset and safeTrail)) + bytes memory data = Storage.load({ storagePointer: storagePointer, length: 34, offset: 31 }); + + assertEq(Bytes.slice1(data, 0), bytes1(0x01)); + assertEq(Bytes.slice32(data, 1), bytes32(0x0200000000000000000000000000000000000000000000000000000000000003)); + assertEq(Bytes.slice1(data, 33), bytes1(0x04)); + assertEq(keccak256(data), keccak256(data1)); + } + + function testStoreLoadFuzzy( + bytes memory data, + bytes32 storagePointer, + uint8 offset + ) public { + Storage.store({ storagePointer: uint256(storagePointer), offset: offset, data: data }); + assertEq( + keccak256(Storage.load({ storagePointer: uint256(storagePointer), length: data.length, offset: offset })), + keccak256(data) + ); + } +} diff --git a/packages/store/test/StoreCore.t.sol b/packages/store/test/StoreCore.t.sol new file mode 100644 index 0000000000..11cd247d76 --- /dev/null +++ b/packages/store/test/StoreCore.t.sol @@ -0,0 +1,618 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import "forge-std/Test.sol"; +import { StoreCore, StoreCoreInternal } from "../src/StoreCore.sol"; +import { Utils } from "../src/Utils.sol"; +import { Bytes } from "../src/Bytes.sol"; +import { SchemaType } from "../src/Types.sol"; +import { Storage } from "../src/Storage.sol"; +import { Memory } from "../src/Memory.sol"; +import { Cast } from "../src/Cast.sol"; +import { Buffer, Buffer_ } from "../src/Buffer.sol"; +import { Schema, SchemaLib } from "../src/Schema.sol"; +import { PackedCounter, PackedCounterLib } from "../src/PackedCounter.sol"; +import { StoreView } from "../src/StoreView.sol"; +import { IStore, IStoreHook } from "../src/IStore.sol"; +import { StoreSwitch } from "../src/StoreSwitch.sol"; + +struct TestStruct { + uint128 firstData; + uint32[] secondData; + uint32[] thirdData; +} + +contract StoreCoreTest is Test, StoreView { + TestStruct private testStruct; + + mapping(uint256 => bytes) private testMapping; + + // Expose an external setRecord function for testing purposes of indexers (see testHooks) + function setRecord( + bytes32 table, + bytes32[] memory key, + bytes memory data + ) public override { + StoreCore.setRecord(table, key, data); + } + + // Expose an external setField function for testing purposes of indexers (see testHooks) + function setField( + bytes32 table, + bytes32[] memory key, + uint8 schemaIndex, + bytes memory data + ) public override { + StoreCore.setField(table, key, schemaIndex, data); + } + + // Expose an external deleteRecord function for testing purposes of indexers (see testHooks) + function deleteRecord(bytes32 table, bytes32[] memory key) public override { + StoreCore.deleteRecord(table, key); + } + + // Expose an external registerSchema function for testing purposes of indexers (see testHooks) + function registerSchema(bytes32 table, Schema schema) public override { + StoreCore.registerSchema(table, schema); + } + + function testRegisterAndGetSchema() public { + Schema schema = SchemaLib.encode(SchemaType.Uint8, SchemaType.Uint16, SchemaType.Uint8, SchemaType.Uint16); + + bytes32 table = keccak256("some.table"); + // !gasreport StoreCore: register schema + StoreCore.registerSchema(table, schema); + + // !gasreport StoreCore: get schema (warm) + Schema loadedSchema = StoreCore.getSchema(table); + + assertEq(schema.unwrap(), loadedSchema.unwrap()); + } + + function testFailRegisterInvalidSchema() public { + StoreCore.registerSchema(keccak256("table"), Schema.wrap(keccak256("random bytes as schema"))); + } + + function testHasSchema() public { + Schema schema = SchemaLib.encode(SchemaType.Uint8, SchemaType.Uint16, SchemaType.Uint8, SchemaType.Uint16); + bytes32 table = keccak256("some.table"); + bytes32 table2 = keccak256("other.table"); + StoreCore.registerSchema(table, schema); + + // !gasreport Check for existence of table (existent) + StoreCore.hasTable(table); + + // !gasreport check for existence of table (non-existent) + StoreCore.hasTable(table2); + + assertTrue(StoreCore.hasTable(table)); + assertFalse(StoreCore.hasTable(table2)); + } + + function testSetAndGetDynamicDataLength() public { + bytes32 table = keccak256("some.table"); + + Schema schema = SchemaLib.encode( + SchemaType.Uint8, + SchemaType.Uint16, + SchemaType.Uint32, + SchemaType.Uint32Array, + SchemaType.Uint32Array + ); + + // Register schema + StoreCore.registerSchema(table, schema); + + // Create some key + bytes32[] memory key = new bytes32[](1); + key[0] = bytes32("some key"); + + // Set dynamic data length of dynamic index 0 + // !gasreport set dynamic length of dynamic index 0 + StoreCoreInternal._setDynamicDataLengthAtIndex(table, key, 0, 10); + + PackedCounter encodedLength = StoreCoreInternal._loadEncodedDynamicDataLength(table, key); + assertEq(encodedLength.atIndex(0), 10); + assertEq(encodedLength.atIndex(1), 0); + assertEq(encodedLength.total(), 10); + + // Set dynamic data length of dynamic index 1 + // !gasreport set dynamic length of dynamic index 1 + StoreCoreInternal._setDynamicDataLengthAtIndex(table, key, 1, 99); + + encodedLength = StoreCoreInternal._loadEncodedDynamicDataLength(table, key); + assertEq(encodedLength.atIndex(0), 10); + assertEq(encodedLength.atIndex(1), 99); + assertEq(encodedLength.total(), 109); + + // Reduce dynamic data length of dynamic index 0 again + // !gasreport reduce dynamic length of dynamic index 0 + StoreCoreInternal._setDynamicDataLengthAtIndex(table, key, 0, 5); + + encodedLength = StoreCoreInternal._loadEncodedDynamicDataLength(table, key); + assertEq(encodedLength.atIndex(0), 5); + assertEq(encodedLength.atIndex(1), 99); + assertEq(encodedLength.total(), 104); + } + + function testSetAndGetStaticData() public { + // Register table's schema + Schema schema = SchemaLib.encode(SchemaType.Uint8, SchemaType.Uint16, SchemaType.Uint8, SchemaType.Uint16); + + bytes32 table = keccak256("some.table"); + StoreCore.registerSchema(table, schema); + + // Set data + bytes memory data = abi.encodePacked(bytes1(0x01), bytes2(0x0203), bytes1(0x04), bytes2(0x0506)); + + bytes32[] memory key = new bytes32[](1); + key[0] = keccak256("some.key"); + + // !gasreport set static record (1 slot) + StoreCore.setRecord(table, key, data); + + // Get data + // !gasreport get static record (1 slot) + bytes memory loadedData = StoreCore.getRecord(table, key, schema); + + assertTrue(Bytes.equals(data, loadedData)); + } + + function testFailSetAndGetStaticData() public { + // Register table's schema + Schema schema = SchemaLib.encode(SchemaType.Uint8, SchemaType.Uint16, SchemaType.Uint8, SchemaType.Uint16); + bytes32 table = keccak256("some.table"); + StoreCore.registerSchema(table, schema); + + // Set data + bytes memory data = abi.encodePacked(bytes1(0x01), bytes2(0x0203), bytes1(0x04)); + + bytes32[] memory key = new bytes32[](1); + key[0] = keccak256("some.key"); + + // This should fail because the data is not 6 bytes long + StoreCore.setRecord(table, key, data); + } + + function testSetAndGetStaticDataSpanningWords() public { + // Register table's schema + Schema schema = SchemaLib.encode(SchemaType.Uint128, SchemaType.Uint256); + bytes32 table = keccak256("some.table"); + StoreCore.registerSchema(table, schema); + + // Set data + bytes memory data = abi.encodePacked( + bytes16(0x0102030405060708090a0b0c0d0e0f10), + bytes32(0x1112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f30) + ); + + bytes32[] memory key = new bytes32[](1); + key[0] = keccak256("some.key"); + + // !gasreport set static record (2 slots) + StoreCore.setRecord(table, key, data); + + // Get data + // !gasreport get static record (2 slots) + bytes memory loadedData = StoreCore.getRecord(table, key, schema); + + assertTrue(Bytes.equals(data, loadedData)); + } + + function testSetAndGetDynamicData() public { + bytes32 table = keccak256("some.table"); + + { + // Register table's schema + Schema schema = SchemaLib.encode(SchemaType.Uint128, SchemaType.Uint32Array, SchemaType.Uint32Array); + StoreCore.registerSchema(table, schema); + } + + bytes16 firstDataBytes = bytes16(0x0102030405060708090a0b0c0d0e0f10); + + bytes memory secondDataBytes; + { + uint32[] memory secondData = new uint32[](2); + secondData[0] = 0x11121314; + secondData[1] = 0x15161718; + secondDataBytes = Bytes.from(secondData); + } + + bytes memory thirdDataBytes; + { + uint32[] memory thirdData = new uint32[](3); + thirdData[0] = 0x191a1b1c; + thirdData[1] = 0x1d1e1f20; + thirdData[2] = 0x21222324; + thirdDataBytes = Bytes.from(thirdData); + } + + PackedCounter encodedDynamicLength; + { + uint16[] memory dynamicLengths = new uint16[](2); + dynamicLengths[0] = uint16(secondDataBytes.length); + dynamicLengths[1] = uint16(thirdDataBytes.length); + encodedDynamicLength = PackedCounterLib.pack(dynamicLengths); + } + + // Concat data + bytes memory data = abi.encodePacked( + firstDataBytes, + encodedDynamicLength.unwrap(), + secondDataBytes, + thirdDataBytes + ); + + // Create key + bytes32[] memory key = new bytes32[](1); + key[0] = bytes32("some.key"); + + // Set data + // !gasreport set complex record with dynamic data (4 slots) + StoreCore.setRecord(table, key, data); + + // Get data + // !gasreport get complex record with dynamic data (4 slots) + bytes memory loadedData = StoreCore.getRecord(table, key); + + assertEq(loadedData.length, data.length); + assertEq(keccak256(loadedData), keccak256(data)); + + // Compare gas - setting the data as raw struct + TestStruct memory _testStruct = TestStruct(0, new uint32[](2), new uint32[](3)); + _testStruct.firstData = 0x0102030405060708090a0b0c0d0e0f10; + _testStruct.secondData[0] = 0x11121314; + _testStruct.secondData[1] = 0x15161718; + _testStruct.thirdData[0] = 0x191a1b1c; + _testStruct.thirdData[1] = 0x1d1e1f20; + _testStruct.thirdData[2] = 0x21222324; + + // !gasreport compare: Set complex record with dynamic data using native solidity + testStruct = _testStruct; + + // !gasreport compare: Set complex record with dynamic data using abi.encode + testMapping[1234] = abi.encode(_testStruct); + } + + function testSetAndGetField() public { + bytes32 table = keccak256("some.table"); + + { + // Register table's schema + Schema schema = SchemaLib.encode( + SchemaType.Uint128, + SchemaType.Uint256, + SchemaType.Uint32Array, + SchemaType.Uint32Array + ); + StoreCore.registerSchema(table, schema); + } + + bytes16 firstDataBytes = bytes16(0x0102030405060708090a0b0c0d0e0f10); + + // Create key + bytes32[] memory key = new bytes32[](1); + key[0] = bytes32("some.key"); + + // Set first field + // !gasreport set static field (1 slot) + StoreCore.setField(table, key, 0, abi.encodePacked(firstDataBytes)); + + //////////////// + // Static data + //////////////// + + // Get first field + // !gasreport get static field (1 slot) + bytes memory loadedData = StoreCore.getField(table, key, 0); + + // Verify loaded data is correct + assertEq(loadedData.length, 16); + assertEq(bytes16(loadedData), bytes16(firstDataBytes)); + + // Verify the second index is not set yet + assertEq(uint256(bytes32(StoreCore.getField(table, key, 1))), 0); + + // Set second field + bytes32 secondDataBytes = keccak256("some data"); + + // !gasreport set static field (overlap 2 slot) + StoreCore.setField(table, key, 1, abi.encodePacked(secondDataBytes)); + + // Get second field + // !gasreport get static field (overlap 2 slot) + loadedData = StoreCore.getField(table, key, 1); + + // Verify loaded data is correct + assertEq(loadedData.length, 32); + assertEq(bytes32(loadedData), secondDataBytes); + + // Verify the first field didn't change + assertEq(bytes16(StoreCore.getField(table, key, 0)), bytes16(firstDataBytes)); + + // Verify the full static data is correct + assertEq(StoreCoreInternal._getStaticData(table, key).length, 48); + assertEq(Bytes.slice16(StoreCoreInternal._getStaticData(table, key), 0), firstDataBytes); + assertEq(Bytes.slice32(StoreCoreInternal._getStaticData(table, key), 16), secondDataBytes); + assertEq( + keccak256(StoreCoreInternal._getStaticData(table, key)), + keccak256(abi.encodePacked(firstDataBytes, secondDataBytes)) + ); + + //////////////// + // Dynamic data + //////////////// + + bytes memory thirdDataBytes; + { + uint32[] memory thirdData = new uint32[](2); + thirdData[0] = 0x11121314; + thirdData[1] = 0x15161718; + thirdDataBytes = Bytes.from(thirdData); + } + + bytes memory fourthDataBytes; + { + uint32[] memory fourthData = new uint32[](3); + fourthData[0] = 0x191a1b1c; + fourthData[1] = 0x1d1e1f20; + fourthData[2] = 0x21222324; + fourthDataBytes = Bytes.from(fourthData); + } + + // Set third field + // !gasreport set dynamic field (1 slot, first dynamic field) + StoreCore.setField(table, key, 2, thirdDataBytes); + + // Get third field + // !gasreport get dynamic field (1 slot, first dynamic field) + loadedData = StoreCore.getField(table, key, 2); + + // Verify loaded data is correct + assertEq(Cast.toUint32Array(Buffer_.fromBytes(loadedData).toArray(4)).length, 2); + assertEq(loadedData.length, thirdDataBytes.length); + assertEq(keccak256(loadedData), keccak256(thirdDataBytes)); + + // Verify the fourth field is not set yet + assertEq(StoreCore.getField(table, key, 3).length, 0); + + // Verify none of the previous fields were impacted + assertEq(bytes16(StoreCore.getField(table, key, 0)), bytes16(firstDataBytes)); + assertEq(bytes32(StoreCore.getField(table, key, 1)), bytes32(secondDataBytes)); + + // Set fourth field + // !gasreport set dynamic field (1 slot, second dynamic field) + StoreCore.setField(table, key, 3, fourthDataBytes); + + // Get fourth field + // !gasreport get dynamic field (1 slot, second dynamic field) + loadedData = StoreCore.getField(table, key, 3); + + // Verify loaded data is correct + assertEq(loadedData.length, fourthDataBytes.length); + assertEq(keccak256(loadedData), keccak256(fourthDataBytes)); + + // Verify all fields are correct + PackedCounter encodedLengths = PackedCounterLib.pack(uint16(thirdDataBytes.length), uint16(fourthDataBytes.length)); + assertEq( + keccak256(StoreCore.getRecord(table, key)), + keccak256( + abi.encodePacked(firstDataBytes, secondDataBytes, encodedLengths.unwrap(), thirdDataBytes, fourthDataBytes) + ) + ); + } + + function testDeleteData() public { + bytes32 table = keccak256("some.table"); + + // Register table's schema + Schema schema = SchemaLib.encode(SchemaType.Uint128, SchemaType.Uint32Array, SchemaType.Uint32Array); + StoreCore.registerSchema(table, schema); + + bytes16 firstDataBytes = bytes16(0x0102030405060708090a0b0c0d0e0f10); + + bytes memory secondDataBytes; + { + uint32[] memory secondData = new uint32[](2); + secondData[0] = 0x11121314; + secondData[1] = 0x15161718; + secondDataBytes = Bytes.from(secondData); + } + + bytes memory thirdDataBytes; + { + uint32[] memory thirdData = new uint32[](3); + thirdData[0] = 0x191a1b1c; + thirdData[1] = 0x1d1e1f20; + thirdData[2] = 0x21222324; + thirdDataBytes = Bytes.from(thirdData); + } + + PackedCounter encodedDynamicLength; + { + uint16[] memory dynamicLengths = new uint16[](2); + dynamicLengths[0] = uint16(secondDataBytes.length); + dynamicLengths[1] = uint16(thirdDataBytes.length); + encodedDynamicLength = PackedCounterLib.pack(dynamicLengths); + } + + // Concat data + bytes memory data = abi.encodePacked( + firstDataBytes, + encodedDynamicLength.unwrap(), + secondDataBytes, + thirdDataBytes + ); + + // Create key + bytes32[] memory key = new bytes32[](1); + key[0] = bytes32("some.key"); + + // Set data + StoreCore.setRecord(table, key, data); + + // Get data + bytes memory loadedData = StoreCore.getRecord(table, key); + + assertEq(loadedData.length, data.length); + assertEq(keccak256(loadedData), keccak256(data)); + + // Delete data + // !gasreport delete record (complex data, 3 slots) + StoreCore.deleteRecord(table, key); + + // Verify data is deleted + loadedData = StoreCore.getRecord(table, key); + assertEq(keccak256(loadedData), keccak256(new bytes(schema.staticDataLength()))); + } + + function testAccessEmptyData() public { + bytes32 table = keccak256("some.table"); + Schema schema = SchemaLib.encode(SchemaType.Uint32, SchemaType.Uint32Array); + + StoreCore.registerSchema(table, schema); + + // Create key + bytes32[] memory key = new bytes32[](1); + key[0] = bytes32("some.key"); + + // !gasreport access non-existing record + bytes memory data1 = StoreCore.getRecord(table, key); + assertEq(data1.length, schema.staticDataLength()); + + // !gasreport access static field of non-existing record + bytes memory data2 = StoreCore.getField(table, key, 0); + assertEq(data2.length, schema.staticDataLength()); + + // !gasreport access dynamic field of non-existing record + bytes memory data3 = StoreCore.getField(table, key, 1); + assertEq(data3.length, 0); + } + + function testHooks() public { + bytes32 table = keccak256("some.table"); + bytes32[] memory key = new bytes32[](1); + key[0] = keccak256("some key"); + + // Register table's schema + Schema schema = SchemaLib.encode(SchemaType.Uint128); + StoreCore.registerSchema(table, schema); + + // Create subscriber + MirrorSubscriber subscriber = new MirrorSubscriber(table, schema); + + // !gasreport register subscriber + StoreCore.registerHook(table, subscriber); + + bytes memory data = abi.encodePacked(bytes16(0x0102030405060708090a0b0c0d0e0f10)); + + // !gasreport set record on table with subscriber + StoreCore.setRecord(table, key, data); + + // Get data from indexed table - the indexer should have mirrored the data there + bytes memory indexedData = StoreCore.getRecord(indexerTableId, key); + assertEq(keccak256(data), keccak256(indexedData)); + + data = abi.encodePacked(bytes16(0x1112131415161718191a1b1c1d1e1f20)); + + // !gasreport set static field on table with subscriber + StoreCore.setField(table, key, 0, data); + + // Get data from indexed table - the indexer should have mirrored the data there + indexedData = StoreCore.getRecord(indexerTableId, key); + assertEq(keccak256(data), keccak256(indexedData)); + + // !gasreport delete record on table with subscriber + StoreCore.deleteRecord(table, key); + + // Get data from indexed table - the indexer should have mirrored the data there + indexedData = StoreCore.getRecord(indexerTableId, key); + assertEq(keccak256(indexedData), keccak256(abi.encodePacked(bytes16(0)))); + } + + function testHooksDynamicData() public { + bytes32 table = keccak256("some.table"); + bytes32[] memory key = new bytes32[](1); + key[0] = keccak256("some key"); + + // Register table's schema + Schema schema = SchemaLib.encode(SchemaType.Uint128, SchemaType.Uint32Array); + StoreCore.registerSchema(table, schema); + + // Create subscriber + MirrorSubscriber subscriber = new MirrorSubscriber(table, schema); + + // !gasreport register subscriber + StoreCore.registerHook(table, subscriber); + + uint32[] memory arrayData = new uint32[](1); + arrayData[0] = 0x01020304; + bytes memory arrayDataBytes = Bytes.from(arrayData); + PackedCounter encodedArrayDataLength = PackedCounterLib.pack(uint16(arrayDataBytes.length)); + bytes memory dynamicData = abi.encodePacked(encodedArrayDataLength.unwrap(), arrayDataBytes); + bytes memory staticData = abi.encodePacked(bytes16(0x0102030405060708090a0b0c0d0e0f10)); + bytes memory data = abi.encodePacked(staticData, dynamicData); + + // !gasreport set (dynamic) record on table with subscriber + StoreCore.setRecord(table, key, data); + + // Get data from indexed table - the indexer should have mirrored the data there + bytes memory indexedData = StoreCore.getRecord(indexerTableId, key); + assertEq(keccak256(data), keccak256(indexedData)); + + // Update dynamic data + arrayData[0] = 0x11121314; + arrayDataBytes = Bytes.from(arrayData); + dynamicData = abi.encodePacked(encodedArrayDataLength.unwrap(), arrayDataBytes); + data = abi.encodePacked(staticData, dynamicData); + + // !gasreport set (dynamic) field on table with subscriber + StoreCore.setField(table, key, 1, arrayDataBytes); + + // Get data from indexed table - the indexer should have mirrored the data there + indexedData = StoreCore.getRecord(indexerTableId, key); + assertEq(keccak256(data), keccak256(indexedData)); + + // !gasreport delete (dynamic) record on table with subscriber + StoreCore.deleteRecord(table, key); + + // Get data from indexed table - the indexer should have mirrored the data there + indexedData = StoreCore.getRecord(indexerTableId, key); + assertEq(keccak256(indexedData), keccak256(abi.encodePacked(bytes16(0)))); + } +} + +bytes32 constant indexerTableId = keccak256("indexer.table"); + +contract MirrorSubscriber is IStoreHook { + bytes32 _table; + + constructor(bytes32 table, Schema schema) { + IStore(msg.sender).registerSchema(indexerTableId, schema); + _table = table; + } + + function onSetRecord( + bytes32 table, + bytes32[] memory key, + bytes memory data + ) public { + if (table != table) revert("invalid table"); + StoreSwitch.setRecord(indexerTableId, key, data); + } + + function onSetField( + bytes32 table, + bytes32[] memory key, + uint8 schemaIndex, + bytes memory data + ) public { + if (table != table) revert("invalid table"); + StoreSwitch.setField(indexerTableId, key, schemaIndex, data); + } + + function onDeleteRecord(bytes32 table, bytes32[] memory key) public { + if (table != table) revert("invalid table"); + StoreSwitch.deleteRecord(indexerTableId, key); + } +} diff --git a/packages/store/test/StoreSwitch.t.sol b/packages/store/test/StoreSwitch.t.sol new file mode 100644 index 0000000000..161f1f06cf --- /dev/null +++ b/packages/store/test/StoreSwitch.t.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import "forge-std/Test.sol"; +import { SchemaType } from "../src/Types.sol"; +import { StoreCore } from "../src/StoreCore.sol"; +import { StoreView } from "../src/StoreView.sol"; +import { StoreSwitch } from "../src/StoreSwitch.sol"; + +// Mock Store to call MockSystem +contract Store is StoreView { + MockSystem mockSystem = new MockSystem(); + + function callViaDelegateCall() public returns (bool isDelegate) { + (bool success, bytes memory data) = address(mockSystem).delegatecall(abi.encodeWithSignature("isDelegateCall()")); + if (!success) revert("delegatecall failed"); + isDelegate = abi.decode(data, (bool)); + } + + function callViaCall() public returns (bool isDelegate) { + (bool success, bytes memory data) = address(mockSystem).call(abi.encodeWithSignature("isDelegateCall()")); + if (!success) revert("delegatecall failed"); + isDelegate = abi.decode(data, (bool)); + } +} + +// Mock system to wrap StoreSwitch.isDelegateCall() +contract MockSystem { + function isDelegateCall() public view returns (bool isDelegate) { + // !gasreport check if delegatecall + isDelegate = StoreSwitch.isDelegateCall(); + } +} + +contract StoreSwitchTest is Test { + Store store; + + function setUp() public { + store = new Store(); + } + + function testIsDelegatecall() public { + bool isDelegate = store.callViaDelegateCall(); + assertTrue(isDelegate); + } + + function testIsNoDelegatecall() public { + bool isDelegate = store.callViaCall(); + assertFalse(isDelegate); + } + + // TODO: tests for setting data on self vs msg.sender +} diff --git a/packages/store/test/System.t.sol b/packages/store/test/System.t.sol new file mode 100644 index 0000000000..0a54d5b7cf --- /dev/null +++ b/packages/store/test/System.t.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import "forge-std/Test.sol"; +import { World } from "../src/World.sol"; +import { System } from "../src/System.sol"; + +contract TestSystem is System { + function msgSender() public pure returns (address) { + // !gasreport extract msg.sender from calldata + address sender = _msgSender(); + return sender; + } +} + +contract SystemTest is Test { + function testMsgSender() public { + TestSystem system = new TestSystem(); + address sender = address(0x123); + (bool success, bytes memory returndata) = address(system).call(abi.encodeWithSignature("msgSender()", sender)); + assertTrue(success); + assertEq(abi.decode(returndata, (address)), sender); + } +} diff --git a/packages/store/test/Vector2Table.t.sol b/packages/store/test/Vector2Table.t.sol new file mode 100644 index 0000000000..29f6632fad --- /dev/null +++ b/packages/store/test/Vector2Table.t.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import "forge-std/Test.sol"; +import { Vector2Table, tableId as Vector2Id, Vector2 } from "../src/tables/Vector2Table.sol"; +import { StoreCore } from "../src/StoreCore.sol"; +import { SchemaType } from "../src/Types.sol"; +import { StoreView } from "../src/StoreView.sol"; +import { Schema } from "../src/Schema.sol"; + +contract Vector2TableTest is Test, StoreView { + function testRegisterAndGetSchema() public { + // !gasreport register Vector2Table schema + Vector2Table.registerSchema(); + + Schema registeredSchema = StoreCore.getSchema(Vector2Id); + Schema declaredSchema = Vector2Table.getSchema(); + + assertEq(keccak256(abi.encode(registeredSchema)), keccak256(abi.encode(declaredSchema))); + } + + function testSetAndGet() public { + Vector2Table.registerSchema(); + bytes32 key = keccak256("somekey"); + + // !gasreport set Vector2Table record + Vector2Table.set({ key: key, x: 1, y: 2 }); + + // !gasreport get Vector2Table record + Vector2 memory vector = Vector2Table.get(key); + + assertEq(vector.x, 1); + assertEq(vector.y, 2); + } +} diff --git a/packages/store/test/World.t.sol b/packages/store/test/World.t.sol new file mode 100644 index 0000000000..f768fc496a --- /dev/null +++ b/packages/store/test/World.t.sol @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import "forge-std/Test.sol"; +import { World } from "../src/World.sol"; +import { System } from "../src/System.sol"; +import { ExecutionMode } from "../src/Types.sol"; +import { Vector2Table, Vector2 } from "../src/tables/Vector2Table.sol"; + +contract WorldTestSystem is System { + function msgSender() public pure returns (address) { + return _msgSender(); + } + + // WorldTestSystem's move function sets state on the Vector2Table of the caller + // (independent of delegatecall or regular call) + function move( + bytes32 entity, + uint32 x, + uint32 y + ) public { + Vector2Table.set({ key: entity, x: x, y: y }); + } +} + +// TODO: auto-generate this interface from registered systems +interface WorldWithWorldTestSystem { + function WorldTestSystem_msgSender() external view returns (address); + + function WorldTestSystem_move( + bytes32 entity, + uint32 x, + uint32 y + ) external; +} + +contract WorldTest is Test { + World internal world; + WorldTestSystem internal system; + + function setUp() public { + world = new World(); + system = new WorldTestSystem(); + } + + function testRegisterAndCallSystem() public { + // Register autonomous system in the world + world.registerSystem(address(system), "WorldTestSystem", "msgSender()", ExecutionMode.Autonomous); + + // Call system via world contract + address msgSender = WorldWithWorldTestSystem(address(world)).WorldTestSystem_msgSender(); + + // msg.sender (this) should have been passed to system + assertEq(msgSender, address(this)); + } + + function testRegisterAndDelegatecallSystem() public { + // Register delegate system in the world + world.registerSystem(address(system), "WorldTestSystem", "msgSender()", ExecutionMode.Delegate); + + // Call system via world contract + address msgSender = WorldWithWorldTestSystem(address(world)).WorldTestSystem_msgSender(); + + // msg.sender (this) should have been passed to system + assertEq(msgSender, address(this)); + } + + function testRegisterVector2Table() public { + // Register table + Vector2Table.registerSchema(world); + } + + // Register WorldTestSystem as autonomous system and call its move function to set state on Vector2Table + function testSetVector2ViaWorldTestSystemAutonomous() public { + // Register autonomous system in the world + world.registerSystem(address(system), "WorldTestSystem", "move(bytes32,uint32,uint32)", ExecutionMode.Autonomous); + + // Register table + Vector2Table.registerSchema(world); + + // Call autonomous system's move function via world contract + bytes32 entity = keccak256("entity"); + + // !gasreport call autonomous system via World contract + WorldWithWorldTestSystem(address(world)).WorldTestSystem_move(entity, 1, 2); + + // Get state from the table (using out-of-system syntax) + Vector2 memory vec2 = Vector2Table.get(world, entity); + + // Verify the state has been set correctly + assertEq(vec2.x, 1); + assertEq(vec2.y, 2); + } + + // Register WorldTestSystem as delegate system and call its move function to set state on Vector2Table + function testSetVector2ViaWorldTestSystemDelegate() public { + // Register delegate system in the world + world.registerSystem(address(system), "WorldTestSystem", "move(bytes32,uint32,uint32)", ExecutionMode.Delegate); + + // Register table + Vector2Table.registerSchema(world); + + // Call delegate system's move function via world contract + bytes32 entity = keccak256("entity"); + + // !gasreport call delegate system via World contract + WorldWithWorldTestSystem(address(world)).WorldTestSystem_move(entity, 1, 2); + + // Get state from the table (using out-of-system syntax) + Vector2 memory vec2 = Vector2Table.get(world, entity); + + // Verify the state has been set correctly + assertEq(vec2.x, 1); + assertEq(vec2.y, 2); + } +} diff --git a/packages/store/test/schemas/AddressArray.t.sol b/packages/store/test/schemas/AddressArray.t.sol new file mode 100644 index 0000000000..10c97ce7f8 --- /dev/null +++ b/packages/store/test/schemas/AddressArray.t.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import "forge-std/Test.sol"; +import { StoreView } from "../../src/StoreView.sol"; +import { AddressArray, AddressArray_ } from "../../src/schemas/AddressArray.sol"; + +bytes32 constant tableId = keccak256("mud.store.table.addressArray"); + +contract AddressArrayTest is Test, StoreView { + function testSetAndGet() public { + AddressArray_.registerSchema(tableId); + bytes32 key = keccak256("somekey"); + + address[] memory addresses = new address[](1); + addresses[0] = address(this); + + // !gasreport set record in AddressArrayTable + AddressArray_.set(tableId, key, addresses); + + // !gasreport get record from AddressArrayTable (warm) + address[] memory returnedAddresses = AddressArray_.get(tableId, key); + + assertEq(returnedAddresses.length, addresses.length); + assertEq(returnedAddresses[0], addresses[0]); + + // !gasreport push record to AddressArrayTable + AddressArray_.push(tableId, key, addresses[0]); + + returnedAddresses = AddressArray_.get(tableId, key); + + assertEq(returnedAddresses.length, 2); + assertEq(returnedAddresses[1], addresses[0]); + } +} diff --git a/packages/store/test/schemas/CallbackArray.t.sol b/packages/store/test/schemas/CallbackArray.t.sol new file mode 100644 index 0000000000..7e52465a3f --- /dev/null +++ b/packages/store/test/schemas/CallbackArray.t.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import "forge-std/Test.sol"; +import { StoreView } from "../../src/StoreView.sol"; +import { CallbackArray, CallbackArray_ } from "../../src/schemas/CallbackArray.sol"; + +bytes32 constant tableId = keccak256("mud.store.table.callbackArray"); + +contract CallbackArrayTest is Test, StoreView { + function testSetAndGet() public { + CallbackArray_.registerSchema(tableId); + bytes32 key = keccak256("somekey"); + + bytes24[] memory callbacks = new bytes24[](1); + callbacks[0] = bytes24(abi.encode(this.testSetAndGet)); + + // !gasreport set record in CallbackArrayTable + CallbackArray_.set(tableId, key, callbacks); + + // !gasreport get record from CallbackArrayTable (warm) + bytes24[] memory returnedCallbacks = CallbackArray_.get(tableId, key); + + assertEq(returnedCallbacks.length, callbacks.length); + assertEq(returnedCallbacks[0], callbacks[0]); + + // !gasreport push record to CallbackArrayTable + CallbackArray_.push(tableId, key, callbacks[0]); + + returnedCallbacks = CallbackArray_.get(tableId, key); + + assertEq(returnedCallbacks.length, 2); + assertEq(returnedCallbacks[1], callbacks[0]); + } +} diff --git a/packages/store/tsconfig.json b/packages/store/tsconfig.json new file mode 100644 index 0000000000..5587243470 --- /dev/null +++ b/packages/store/tsconfig.json @@ -0,0 +1,102 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + + /* Projects */ + // "incremental": true, /* Enable incremental compilation */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "es2019" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */ + // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + + /* Modules */ + // "module": "esnext" /* Specify what module code is generated. */, + // "rootDir": "." /* Specify the root folder within your source files. */, + "moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */, + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */ + "types": ["mocha"] /* Specify type package names to be included without being referenced in a source file. */, + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "resolveJsonModule": true, /* Enable importing .json files */ + // "noResolve": true, /* Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */ + + /* Emit */ + // "declaration": true /* Generate .d.ts files from TypeScript and JavaScript files in your project. */, + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true /* Only output d.ts files and not JavaScript files. */, + // "sourceMap": true /* Create source map files for emitted JavaScript files. */, + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "dist" /* Specify an output folder for all emitted files. */, + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true /* Ensure that each file can be safely transpiled without relying on other imports. */, + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + // "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */ + + /* Type Checking */ + // "strict": true /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */ + // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */ + // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + // "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } + // "exclude": ["dist", "**/*.spec.ts", "packages"] +} diff --git a/packages/store/yarn.lock b/packages/store/yarn.lock new file mode 100644 index 0000000000..59f8b2244e --- /dev/null +++ b/packages/store/yarn.lock @@ -0,0 +1,3309 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/code-frame@^7.0.0": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" + integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== + dependencies: + "@babel/highlight" "^7.18.6" + +"@babel/helper-validator-identifier@^7.18.6": + version "7.19.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" + integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== + +"@babel/highlight@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" + integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== + dependencies: + "@babel/helper-validator-identifier" "^7.18.6" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@cspotcode/source-map-consumer@0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b" + integrity sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg== + +"@cspotcode/source-map-support@0.7.0": + version "0.7.0" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz#4789840aa859e46d2f3173727ab707c66bf344f5" + integrity sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA== + dependencies: + "@cspotcode/source-map-consumer" "0.8.0" + +"@ethersproject/abi@^5.1.2": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.7.0.tgz#b3f3e045bbbeed1af3947335c247ad625a44e449" + integrity sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA== + dependencies: + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/abstract-provider@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz#b0a8550f88b6bf9d51f90e4795d48294630cb9ef" + integrity sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/networks" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/web" "^5.7.0" + +"@ethersproject/abstract-signer@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz#13f4f32117868452191a4649723cb086d2b596b2" + integrity sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + +"@ethersproject/address@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.7.0.tgz#19b56c4d74a3b0a46bfdbb6cfcc0a153fc697f37" + integrity sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + +"@ethersproject/base64@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.7.0.tgz#ac4ee92aa36c1628173e221d0d01f53692059e1c" + integrity sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ== + dependencies: + "@ethersproject/bytes" "^5.7.0" + +"@ethersproject/bignumber@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.7.0.tgz#e2f03837f268ba655ffba03a57853e18a18dc9c2" + integrity sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + bn.js "^5.2.1" + +"@ethersproject/bytes@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.7.0.tgz#a00f6ea8d7e7534d6d87f47188af1148d71f155d" + integrity sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/constants@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.7.0.tgz#df80a9705a7e08984161f09014ea012d1c75295e" + integrity sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + +"@ethersproject/hash@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.7.0.tgz#eb7aca84a588508369562e16e514b539ba5240a7" + integrity sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/base64" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/keccak256@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.7.0.tgz#3186350c6e1cd6aba7940384ec7d6d9db01f335a" + integrity sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg== + dependencies: + "@ethersproject/bytes" "^5.7.0" + js-sha3 "0.8.0" + +"@ethersproject/logger@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.7.0.tgz#6ce9ae168e74fecf287be17062b590852c311892" + integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig== + +"@ethersproject/networks@^5.7.0": + version "5.7.1" + resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.7.1.tgz#118e1a981d757d45ccea6bb58d9fd3d9db14ead6" + integrity sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/properties@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.7.0.tgz#a6e12cb0439b878aaf470f1902a176033067ed30" + integrity sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/rlp@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.7.0.tgz#de39e4d5918b9d74d46de93af80b7685a9c21304" + integrity sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/signing-key@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.7.0.tgz#06b2df39411b00bc57c7c09b01d1e41cf1b16ab3" + integrity sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + bn.js "^5.2.1" + elliptic "6.5.4" + hash.js "1.1.7" + +"@ethersproject/strings@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.7.0.tgz#54c9d2a7c57ae8f1205c88a9d3a56471e14d5ed2" + integrity sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/transactions@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.7.0.tgz#91318fc24063e057885a6af13fdb703e1f993d3b" + integrity sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ== + dependencies: + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + +"@ethersproject/web@^5.7.0": + version "5.7.1" + resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.7.1.tgz#de1f285b373149bee5928f4eb7bcb87ee5fbb4ae" + integrity sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w== + dependencies: + "@ethersproject/base64" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@metamask/eth-sig-util@^4.0.0": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@metamask/eth-sig-util/-/eth-sig-util-4.0.1.tgz#3ad61f6ea9ad73ba5b19db780d40d9aae5157088" + integrity sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ== + dependencies: + ethereumjs-abi "^0.6.8" + ethereumjs-util "^6.2.1" + ethjs-util "^0.1.6" + tweetnacl "^1.0.3" + tweetnacl-util "^0.15.1" + +"@morgan-stanley/ts-mocking-bird@^0.6.2": + version "0.6.4" + resolved "https://registry.yarnpkg.com/@morgan-stanley/ts-mocking-bird/-/ts-mocking-bird-0.6.4.tgz#2e4b60d42957bab3b50b67dbf14c3da2f62a39f7" + integrity sha512-57VJIflP8eR2xXa9cD1LUawh+Gh+BVQfVu0n6GALyg/AqV/Nz25kDRvws3i9kIe1PTrbsZZOYpsYp6bXPd6nVA== + dependencies: + lodash "^4.17.16" + uuid "^7.0.3" + +"@noble/hashes@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.1.2.tgz#e9e035b9b166ca0af657a7848eb2718f0f22f183" + integrity sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA== + +"@noble/hashes@~1.1.1": + version "1.1.5" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.1.5.tgz#1a0377f3b9020efe2fae03290bd2a12140c95c11" + integrity sha512-LTMZiiLc+V4v1Yi16TD6aX2gmtKszNye0pQgbaLqkvhIqP7nVsSaJsWloGQjJfJ8offaoP5GtX3yY5swbcJxxQ== + +"@noble/secp256k1@1.6.3", "@noble/secp256k1@~1.6.0": + version "1.6.3" + resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.6.3.tgz#7eed12d9f4404b416999d0c87686836c4c5c9b94" + integrity sha512-T04e4iTurVy7I8Sw4+c5OSN9/RkPlo1uKxAomtxQNLq8j1uPAqnsqG1bqvY3Jv7c13gyr6dui0zmh/I3+f/JaQ== + +"@nomicfoundation/ethereumjs-block@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-block/-/ethereumjs-block-4.0.0.tgz#fdd5c045e7baa5169abeed0e1202bf94e4481c49" + integrity sha512-bk8uP8VuexLgyIZAHExH1QEovqx0Lzhc9Ntm63nCRKLHXIZkobaFaeCVwTESV7YkPKUk7NiK11s8ryed4CS9yA== + dependencies: + "@nomicfoundation/ethereumjs-common" "^3.0.0" + "@nomicfoundation/ethereumjs-rlp" "^4.0.0" + "@nomicfoundation/ethereumjs-trie" "^5.0.0" + "@nomicfoundation/ethereumjs-tx" "^4.0.0" + "@nomicfoundation/ethereumjs-util" "^8.0.0" + ethereum-cryptography "0.1.3" + +"@nomicfoundation/ethereumjs-blockchain@^6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-blockchain/-/ethereumjs-blockchain-6.0.0.tgz#1a8c243a46d4d3691631f139bfb3a4a157187b0c" + integrity sha512-pLFEoea6MWd81QQYSReLlLfH7N9v7lH66JC/NMPN848ySPPQA5renWnE7wPByfQFzNrPBuDDRFFULMDmj1C0xw== + dependencies: + "@nomicfoundation/ethereumjs-block" "^4.0.0" + "@nomicfoundation/ethereumjs-common" "^3.0.0" + "@nomicfoundation/ethereumjs-ethash" "^2.0.0" + "@nomicfoundation/ethereumjs-rlp" "^4.0.0" + "@nomicfoundation/ethereumjs-trie" "^5.0.0" + "@nomicfoundation/ethereumjs-util" "^8.0.0" + abstract-level "^1.0.3" + debug "^4.3.3" + ethereum-cryptography "0.1.3" + level "^8.0.0" + lru-cache "^5.1.1" + memory-level "^1.0.0" + +"@nomicfoundation/ethereumjs-common@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-3.0.0.tgz#f6bcc7753994555e49ab3aa517fc8bcf89c280b9" + integrity sha512-WS7qSshQfxoZOpHG/XqlHEGRG1zmyjYrvmATvc4c62+gZXgre1ymYP8ZNgx/3FyZY0TWe9OjFlKOfLqmgOeYwA== + dependencies: + "@nomicfoundation/ethereumjs-util" "^8.0.0" + crc-32 "^1.2.0" + +"@nomicfoundation/ethereumjs-ethash@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-ethash/-/ethereumjs-ethash-2.0.0.tgz#11539c32fe0990e1122ff987d1b84cfa34774e81" + integrity sha512-WpDvnRncfDUuXdsAXlI4lXbqUDOA+adYRQaEezIkxqDkc+LDyYDbd/xairmY98GnQzo1zIqsIL6GB5MoMSJDew== + dependencies: + "@nomicfoundation/ethereumjs-block" "^4.0.0" + "@nomicfoundation/ethereumjs-rlp" "^4.0.0" + "@nomicfoundation/ethereumjs-util" "^8.0.0" + abstract-level "^1.0.3" + bigint-crypto-utils "^3.0.23" + ethereum-cryptography "0.1.3" + +"@nomicfoundation/ethereumjs-evm@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-evm/-/ethereumjs-evm-1.0.0.tgz#99cd173c03b59107c156a69c5e215409098a370b" + integrity sha512-hVS6qRo3V1PLKCO210UfcEQHvlG7GqR8iFzp0yyjTg2TmJQizcChKgWo8KFsdMw6AyoLgLhHGHw4HdlP8a4i+Q== + dependencies: + "@nomicfoundation/ethereumjs-common" "^3.0.0" + "@nomicfoundation/ethereumjs-util" "^8.0.0" + "@types/async-eventemitter" "^0.2.1" + async-eventemitter "^0.2.4" + debug "^4.3.3" + ethereum-cryptography "0.1.3" + mcl-wasm "^0.7.1" + rustbn.js "~0.2.0" + +"@nomicfoundation/ethereumjs-rlp@^4.0.0", "@nomicfoundation/ethereumjs-rlp@^4.0.0-beta.2": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-4.0.0.tgz#d9a9c5f0f10310c8849b6525101de455a53e771d" + integrity sha512-GaSOGk5QbUk4eBP5qFbpXoZoZUj/NrW7MRa0tKY4Ew4c2HAS0GXArEMAamtFrkazp0BO4K5p2ZCG3b2FmbShmw== + +"@nomicfoundation/ethereumjs-statemanager@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-statemanager/-/ethereumjs-statemanager-1.0.0.tgz#14a9d4e1c828230368f7ab520c144c34d8721e4b" + integrity sha512-jCtqFjcd2QejtuAMjQzbil/4NHf5aAWxUc+CvS0JclQpl+7M0bxMofR2AJdtz+P3u0ke2euhYREDiE7iSO31vQ== + dependencies: + "@nomicfoundation/ethereumjs-common" "^3.0.0" + "@nomicfoundation/ethereumjs-rlp" "^4.0.0" + "@nomicfoundation/ethereumjs-trie" "^5.0.0" + "@nomicfoundation/ethereumjs-util" "^8.0.0" + debug "^4.3.3" + ethereum-cryptography "0.1.3" + functional-red-black-tree "^1.0.1" + +"@nomicfoundation/ethereumjs-trie@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-trie/-/ethereumjs-trie-5.0.0.tgz#dcfbe3be53a94bc061c9767a396c16702bc2f5b7" + integrity sha512-LIj5XdE+s+t6WSuq/ttegJzZ1vliwg6wlb+Y9f4RlBpuK35B9K02bO7xU+E6Rgg9RGptkWd6TVLdedTI4eNc2A== + dependencies: + "@nomicfoundation/ethereumjs-rlp" "^4.0.0" + "@nomicfoundation/ethereumjs-util" "^8.0.0" + ethereum-cryptography "0.1.3" + readable-stream "^3.6.0" + +"@nomicfoundation/ethereumjs-tx@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-4.0.0.tgz#59dc7452b0862b30342966f7052ab9a1f7802f52" + integrity sha512-Gg3Lir2lNUck43Kp/3x6TfBNwcWC9Z1wYue9Nz3v4xjdcv6oDW9QSMJxqsKw9QEGoBBZ+gqwpW7+F05/rs/g1w== + dependencies: + "@nomicfoundation/ethereumjs-common" "^3.0.0" + "@nomicfoundation/ethereumjs-rlp" "^4.0.0" + "@nomicfoundation/ethereumjs-util" "^8.0.0" + ethereum-cryptography "0.1.3" + +"@nomicfoundation/ethereumjs-util@^8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-8.0.0.tgz#deb2b15d2c308a731e82977aefc4e61ca0ece6c5" + integrity sha512-2emi0NJ/HmTG+CGY58fa+DQuAoroFeSH9gKu9O6JnwTtlzJtgfTixuoOqLEgyyzZVvwfIpRueuePb8TonL1y+A== + dependencies: + "@nomicfoundation/ethereumjs-rlp" "^4.0.0-beta.2" + ethereum-cryptography "0.1.3" + +"@nomicfoundation/ethereumjs-vm@^6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-vm/-/ethereumjs-vm-6.0.0.tgz#2bb50d332bf41790b01a3767ffec3987585d1de6" + integrity sha512-JMPxvPQ3fzD063Sg3Tp+UdwUkVxMoo1uML6KSzFhMH3hoQi/LMuXBoEHAoW83/vyNS9BxEe6jm6LmT5xdeEJ6w== + dependencies: + "@nomicfoundation/ethereumjs-block" "^4.0.0" + "@nomicfoundation/ethereumjs-blockchain" "^6.0.0" + "@nomicfoundation/ethereumjs-common" "^3.0.0" + "@nomicfoundation/ethereumjs-evm" "^1.0.0" + "@nomicfoundation/ethereumjs-rlp" "^4.0.0" + "@nomicfoundation/ethereumjs-statemanager" "^1.0.0" + "@nomicfoundation/ethereumjs-trie" "^5.0.0" + "@nomicfoundation/ethereumjs-tx" "^4.0.0" + "@nomicfoundation/ethereumjs-util" "^8.0.0" + "@types/async-eventemitter" "^0.2.1" + async-eventemitter "^0.2.4" + debug "^4.3.3" + ethereum-cryptography "0.1.3" + functional-red-black-tree "^1.0.1" + mcl-wasm "^0.7.1" + rustbn.js "~0.2.0" + +"@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.0.tgz#83a7367342bd053a76d04bbcf4f373fef07cf760" + integrity sha512-vEF3yKuuzfMHsZecHQcnkUrqm8mnTWfJeEVFHpg+cO+le96xQA4lAJYdUan8pXZohQxv1fSReQsn4QGNuBNuCw== + +"@nomicfoundation/solidity-analyzer-darwin-x64@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-darwin-x64/-/solidity-analyzer-darwin-x64-0.1.0.tgz#1225f7da647ae1ad25a87125664704ecc0af6ccc" + integrity sha512-dlHeIg0pTL4dB1l9JDwbi/JG6dHQaU1xpDK+ugYO8eJ1kxx9Dh2isEUtA4d02cQAl22cjOHTvifAk96A+ItEHA== + +"@nomicfoundation/solidity-analyzer-freebsd-x64@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-freebsd-x64/-/solidity-analyzer-freebsd-x64-0.1.0.tgz#dbc052dcdfd50ae50fd5ae1788b69b4e0fa40040" + integrity sha512-WFCZYMv86WowDA4GiJKnebMQRt3kCcFqHeIomW6NMyqiKqhK1kIZCxSLDYsxqlx396kKLPN1713Q1S8tu68GKg== + +"@nomicfoundation/solidity-analyzer-linux-arm64-gnu@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-linux-arm64-gnu/-/solidity-analyzer-linux-arm64-gnu-0.1.0.tgz#e6b2eea633995b557e74e881d2a43eab4760903d" + integrity sha512-DTw6MNQWWlCgc71Pq7CEhEqkb7fZnS7oly13pujs4cMH1sR0JzNk90Mp1zpSCsCs4oKan2ClhMlLKtNat/XRKQ== + +"@nomicfoundation/solidity-analyzer-linux-arm64-musl@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-linux-arm64-musl/-/solidity-analyzer-linux-arm64-musl-0.1.0.tgz#af81107f5afa794f19988a368647727806e18dc4" + integrity sha512-wUpUnR/3GV5Da88MhrxXh/lhb9kxh9V3Jya2NpBEhKDIRCDmtXMSqPMXHZmOR9DfCwCvG6vLFPr/+YrPCnUN0w== + +"@nomicfoundation/solidity-analyzer-linux-x64-gnu@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-linux-x64-gnu/-/solidity-analyzer-linux-x64-gnu-0.1.0.tgz#6877e1da1a06a9f08446070ab6e0a5347109f868" + integrity sha512-lR0AxK1x/MeKQ/3Pt923kPvwigmGX3OxeU5qNtQ9pj9iucgk4PzhbS3ruUeSpYhUxG50jN4RkIGwUMoev5lguw== + +"@nomicfoundation/solidity-analyzer-linux-x64-musl@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-linux-x64-musl/-/solidity-analyzer-linux-x64-musl-0.1.0.tgz#bb6cd83a0c259eccef4183796b6329a66cf7ebd9" + integrity sha512-A1he/8gy/JeBD3FKvmI6WUJrGrI5uWJNr5Xb9WdV+DK0F8msuOqpEByLlnTdLkXMwW7nSl3awvLezOs9xBHJEg== + +"@nomicfoundation/solidity-analyzer-win32-arm64-msvc@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-win32-arm64-msvc/-/solidity-analyzer-win32-arm64-msvc-0.1.0.tgz#9d4bca1cc9a1333fde985675083b0b7d165f6076" + integrity sha512-7x5SXZ9R9H4SluJZZP8XPN+ju7Mx+XeUMWZw7ZAqkdhP5mK19I4vz3x0zIWygmfE8RT7uQ5xMap0/9NPsO+ykw== + +"@nomicfoundation/solidity-analyzer-win32-ia32-msvc@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-win32-ia32-msvc/-/solidity-analyzer-win32-ia32-msvc-0.1.0.tgz#0db5bfc6aa952bea4098d8d2c8947b4e5c4337ee" + integrity sha512-m7w3xf+hnE774YRXu+2mGV7RiF3QJtUoiYU61FascCkQhX3QMQavh7saH/vzb2jN5D24nT/jwvaHYX/MAM9zUw== + +"@nomicfoundation/solidity-analyzer-win32-x64-msvc@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-win32-x64-msvc/-/solidity-analyzer-win32-x64-msvc-0.1.0.tgz#2e0f39a2924dcd77db6b419828595e984fabcb33" + integrity sha512-xCuybjY0sLJQnJhupiFAXaek2EqF0AP0eBjgzaalPXSNvCEN6ZYHvUzdA50ENDVeSYFXcUsYf3+FsD3XKaeptA== + +"@nomicfoundation/solidity-analyzer@^0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer/-/solidity-analyzer-0.1.0.tgz#e5ddc43ad5c0aab96e5054520d8e16212e125f50" + integrity sha512-xGWAiVCGOycvGiP/qrlf9f9eOn7fpNbyJygcB0P21a1MDuVPlKt0Srp7rvtBEutYQ48ouYnRXm33zlRnlTOPHg== + optionalDependencies: + "@nomicfoundation/solidity-analyzer-darwin-arm64" "0.1.0" + "@nomicfoundation/solidity-analyzer-darwin-x64" "0.1.0" + "@nomicfoundation/solidity-analyzer-freebsd-x64" "0.1.0" + "@nomicfoundation/solidity-analyzer-linux-arm64-gnu" "0.1.0" + "@nomicfoundation/solidity-analyzer-linux-arm64-musl" "0.1.0" + "@nomicfoundation/solidity-analyzer-linux-x64-gnu" "0.1.0" + "@nomicfoundation/solidity-analyzer-linux-x64-musl" "0.1.0" + "@nomicfoundation/solidity-analyzer-win32-arm64-msvc" "0.1.0" + "@nomicfoundation/solidity-analyzer-win32-ia32-msvc" "0.1.0" + "@nomicfoundation/solidity-analyzer-win32-x64-msvc" "0.1.0" + +"@scure/base@~1.1.0": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.1.tgz#ebb651ee52ff84f420097055f4bf46cfba403938" + integrity sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA== + +"@scure/bip32@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.1.0.tgz#dea45875e7fbc720c2b4560325f1cf5d2246d95b" + integrity sha512-ftTW3kKX54YXLCxH6BB7oEEoJfoE2pIgw7MINKAs5PsS6nqKPuKk1haTF/EuHmYqG330t5GSrdmtRuHaY1a62Q== + dependencies: + "@noble/hashes" "~1.1.1" + "@noble/secp256k1" "~1.6.0" + "@scure/base" "~1.1.0" + +"@scure/bip39@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.1.0.tgz#92f11d095bae025f166bef3defcc5bf4945d419a" + integrity sha512-pwrPOS16VeTKg98dYXQyIjJEcWfz7/1YJIwxUEPFfQPtc86Ym/1sVgQ2RLoD43AazMk2l/unK4ITySSpW2+82w== + dependencies: + "@noble/hashes" "~1.1.1" + "@scure/base" "~1.1.0" + +"@sentry/core@5.30.0": + version "5.30.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-5.30.0.tgz#6b203664f69e75106ee8b5a2fe1d717379b331f3" + integrity sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg== + dependencies: + "@sentry/hub" "5.30.0" + "@sentry/minimal" "5.30.0" + "@sentry/types" "5.30.0" + "@sentry/utils" "5.30.0" + tslib "^1.9.3" + +"@sentry/hub@5.30.0": + version "5.30.0" + resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-5.30.0.tgz#2453be9b9cb903404366e198bd30c7ca74cdc100" + integrity sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ== + dependencies: + "@sentry/types" "5.30.0" + "@sentry/utils" "5.30.0" + tslib "^1.9.3" + +"@sentry/minimal@5.30.0": + version "5.30.0" + resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-5.30.0.tgz#ce3d3a6a273428e0084adcb800bc12e72d34637b" + integrity sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw== + dependencies: + "@sentry/hub" "5.30.0" + "@sentry/types" "5.30.0" + tslib "^1.9.3" + +"@sentry/node@^5.18.1": + version "5.30.0" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-5.30.0.tgz#4ca479e799b1021285d7fe12ac0858951c11cd48" + integrity sha512-Br5oyVBF0fZo6ZS9bxbJZG4ApAjRqAnqFFurMVJJdunNb80brh7a5Qva2kjhm+U6r9NJAB5OmDyPkA1Qnt+QVg== + dependencies: + "@sentry/core" "5.30.0" + "@sentry/hub" "5.30.0" + "@sentry/tracing" "5.30.0" + "@sentry/types" "5.30.0" + "@sentry/utils" "5.30.0" + cookie "^0.4.1" + https-proxy-agent "^5.0.0" + lru_map "^0.3.3" + tslib "^1.9.3" + +"@sentry/tracing@5.30.0": + version "5.30.0" + resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-5.30.0.tgz#501d21f00c3f3be7f7635d8710da70d9419d4e1f" + integrity sha512-dUFowCr0AIMwiLD7Fs314Mdzcug+gBVo/+NCMyDw8tFxJkwWAKl7Qa2OZxLQ0ZHjakcj1hNKfCQJ9rhyfOl4Aw== + dependencies: + "@sentry/hub" "5.30.0" + "@sentry/minimal" "5.30.0" + "@sentry/types" "5.30.0" + "@sentry/utils" "5.30.0" + tslib "^1.9.3" + +"@sentry/types@5.30.0": + version "5.30.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-5.30.0.tgz#19709bbe12a1a0115bc790b8942917da5636f402" + integrity sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw== + +"@sentry/utils@5.30.0": + version "5.30.0" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-5.30.0.tgz#9a5bd7ccff85ccfe7856d493bffa64cabc41e980" + integrity sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww== + dependencies: + "@sentry/types" "5.30.0" + tslib "^1.9.3" + +"@solidity-parser/parser@^0.14.5": + version "0.14.5" + resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.14.5.tgz#87bc3cc7b068e08195c219c91cd8ddff5ef1a804" + integrity sha512-6dKnHZn7fg/iQATVEzqyUOyEidbn05q7YA2mQ9hC0MMXhhV3/JrsxmFSYZAcr7j1yUP700LLhTruvJ3MiQmjJg== + dependencies: + antlr4ts "^0.5.0-alpha.4" + +"@tsconfig/node10@^1.0.7": + version "1.0.9" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" + integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== + +"@tsconfig/node12@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" + integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== + +"@tsconfig/node14@^1.0.0": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" + integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== + +"@tsconfig/node16@^1.0.2": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e" + integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ== + +"@typechain/ethers-v5@^9.0.0": + version "9.0.0" + resolved "https://registry.yarnpkg.com/@typechain/ethers-v5/-/ethers-v5-9.0.0.tgz#6aa93bea7425c0463bd8a61eea3643540ef851bd" + integrity sha512-bAanuPl1L2itaUdMvor/QvwnIH+TM/CmG00q17Ilv3ZZMeJ2j8HcarhgJUZ9pBY1teBb85P8cC03dz3mSSx+tQ== + dependencies: + lodash "^4.17.15" + ts-essentials "^7.0.1" + +"@types/async-eventemitter@^0.2.1": + version "0.2.1" + resolved "https://registry.yarnpkg.com/@types/async-eventemitter/-/async-eventemitter-0.2.1.tgz#f8e6280e87e8c60b2b938624b0a3530fb3e24712" + integrity sha512-M2P4Ng26QbAeITiH7w1d7OxtldgfAe0wobpyJzVK/XOb0cUGKU2R4pfAhqcJBXAe2ife5ZOhSv4wk7p+ffURtg== + +"@types/bn.js@^4.11.3": + version "4.11.6" + resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-4.11.6.tgz#c306c70d9358aaea33cd4eda092a742b9505967c" + integrity sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg== + dependencies: + "@types/node" "*" + +"@types/bn.js@^5.1.0": + version "5.1.1" + resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.1.tgz#b51e1b55920a4ca26e9285ff79936bbdec910682" + integrity sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g== + dependencies: + "@types/node" "*" + +"@types/lru-cache@^5.1.0": + version "5.1.1" + resolved "https://registry.yarnpkg.com/@types/lru-cache/-/lru-cache-5.1.1.tgz#c48c2e27b65d2a153b19bfc1a317e30872e01eef" + integrity sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw== + +"@types/mocha@^9.1.1": + version "9.1.1" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-9.1.1.tgz#e7c4f1001eefa4b8afbd1eee27a237fee3bf29c4" + integrity sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw== + +"@types/node@*": + version "18.11.18" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.18.tgz#8dfb97f0da23c2293e554c5a50d61ef134d7697f" + integrity sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA== + +"@types/pbkdf2@^3.0.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@types/pbkdf2/-/pbkdf2-3.1.0.tgz#039a0e9b67da0cdc4ee5dab865caa6b267bb66b1" + integrity sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ== + dependencies: + "@types/node" "*" + +"@types/prettier@^2.1.1": + version "2.7.2" + resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.2.tgz#6c2324641cc4ba050a8c710b2b251b377581fbf0" + integrity sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg== + +"@types/secp256k1@^4.0.1": + version "4.0.3" + resolved "https://registry.yarnpkg.com/@types/secp256k1/-/secp256k1-4.0.3.tgz#1b8e55d8e00f08ee7220b4d59a6abe89c37a901c" + integrity sha512-Da66lEIFeIz9ltsdMZcpQvmrmmoqrfju8pm1BH8WbYjZSwUgCwXLb9C+9XYogwBITnbsSaMdVPb2ekf7TV+03w== + dependencies: + "@types/node" "*" + +abort-controller@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== + dependencies: + event-target-shim "^5.0.0" + +abstract-level@^1.0.0, abstract-level@^1.0.2, abstract-level@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/abstract-level/-/abstract-level-1.0.3.tgz#78a67d3d84da55ee15201486ab44c09560070741" + integrity sha512-t6jv+xHy+VYwc4xqZMn2Pa9DjcdzvzZmQGRjTFc8spIbRGHgBrEKbPq+rYXc7CCo0lxgYvSgKVg9qZAhpVQSjA== + dependencies: + buffer "^6.0.3" + catering "^2.1.0" + is-buffer "^2.0.5" + level-supports "^4.0.0" + level-transcoder "^1.0.1" + module-error "^1.0.1" + queue-microtask "^1.2.3" + +acorn-jsx@^5.0.0: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn-walk@^8.1.1: + version "8.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" + integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== + +acorn@^6.0.7: + version "6.4.2" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" + integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== + +acorn@^8.4.1: + version "8.8.2" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" + integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== + +adm-zip@^0.4.16: + version "0.4.16" + resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.16.tgz#cf4c508fdffab02c269cbc7f471a875f05570365" + integrity sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg== + +agent-base@6: + version "6.0.2" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== + dependencies: + debug "4" + +aggregate-error@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + +ajv@^6.10.2, ajv@^6.6.1, ajv@^6.9.1: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-colors@4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== + +ansi-colors@^4.1.1: + version "4.1.3" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" + integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== + +ansi-escapes@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" + integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== + +ansi-escapes@^4.3.0: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-regex@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.1.tgz#123d6479e92ad45ad897d4054e3c7ca7db4944e1" + integrity sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw== + +ansi-regex@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed" + integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^3.2.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +antlr4@4.7.1: + version "4.7.1" + resolved "https://registry.yarnpkg.com/antlr4/-/antlr4-4.7.1.tgz#69984014f096e9e775f53dd9744bf994d8959773" + integrity sha512-haHyTW7Y9joE5MVs37P2lNYfU2RWBLfcRDD8OWldcdZm5TiCE91B5Xl1oWSwiDUSd4rlExpt2pu1fksYQjRBYQ== + +antlr4ts@^0.5.0-alpha.4: + version "0.5.0-alpha.4" + resolved "https://registry.yarnpkg.com/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz#71702865a87478ed0b40c0709f422cf14d51652a" + integrity sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ== + +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +array-back@^3.0.1, array-back@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/array-back/-/array-back-3.1.0.tgz#b8859d7a508871c9a7b2cf42f99428f65e96bfb0" + integrity sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q== + +array-back@^4.0.1, array-back@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/array-back/-/array-back-4.0.2.tgz#8004e999a6274586beeb27342168652fdb89fa1e" + integrity sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg== + +ast-parents@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/ast-parents/-/ast-parents-0.0.1.tgz#508fd0f05d0c48775d9eccda2e174423261e8dd3" + integrity sha512-XHusKxKz3zoYk1ic8Un640joHbFMhbqneyoZfoKnEGtf2ey9Uh/IdpcQplODdO/kENaMIWsD0nJm4+wX3UNLHA== + +astral-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" + integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== + +async-eventemitter@^0.2.4: + version "0.2.4" + resolved "https://registry.yarnpkg.com/async-eventemitter/-/async-eventemitter-0.2.4.tgz#f5e7c8ca7d3e46aab9ec40a292baf686a0bafaca" + integrity sha512-pd20BwL7Yt1zwDFy+8MX8F1+WCT8aQeKj0kQnTrH9WaeRETlRamVhD0JtRPmrV4GfOJ2F9CvdQkZeZhnh2TuHw== + dependencies: + async "^2.4.0" + +async@^2.4.0: + version "2.6.4" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221" + integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA== + dependencies: + lodash "^4.17.14" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base-x@^3.0.2: + version "3.0.9" + resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320" + integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ== + dependencies: + safe-buffer "^5.0.1" + +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +bigint-crypto-utils@^3.0.23: + version "3.1.8" + resolved "https://registry.yarnpkg.com/bigint-crypto-utils/-/bigint-crypto-utils-3.1.8.tgz#e2e0f40cf45488f9d7f0e32ff84152aa73819d5d" + integrity sha512-+VMV9Laq8pXLBKKKK49nOoq9bfR3j7NNQAtbA617a4nw9bVLo8rsqkKMBgM2AJWlNX9fEIyYaYX+d0laqYV4tw== + dependencies: + bigint-mod-arith "^3.1.0" + +bigint-mod-arith@^3.1.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/bigint-mod-arith/-/bigint-mod-arith-3.1.2.tgz#658e416bc593a463d97b59766226d0a3021a76b1" + integrity sha512-nx8J8bBeiRR+NlsROFH9jHswW5HO8mgfOSqW0AmjicMMvaONDa8AO+5ViKDUUNytBPWiwfvZP4/Bj4Y3lUfvgQ== + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +blakejs@^1.1.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.2.1.tgz#5057e4206eadb4a97f7c0b6e197a505042fc3814" + integrity sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ== + +bn.js@^4.11.0, bn.js@^4.11.8, bn.js@^4.11.9: + version "4.12.0" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" + integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== + +bn.js@^5.2.0, bn.js@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" + integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +brorand@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== + +browser-level@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browser-level/-/browser-level-1.0.1.tgz#36e8c3183d0fe1c405239792faaab5f315871011" + integrity sha512-XECYKJ+Dbzw0lbydyQuJzwNXtOpbMSq737qxJN11sIRTErOMShvDpbzTlgju7orJKvx4epULolZAuJGLzCmWRQ== + dependencies: + abstract-level "^1.0.2" + catering "^2.1.1" + module-error "^1.0.2" + run-parallel-limit "^1.1.0" + +browser-stdout@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== + +browserify-aes@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +bs58@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" + integrity sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw== + dependencies: + base-x "^3.0.2" + +bs58check@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/bs58check/-/bs58check-2.1.2.tgz#53b018291228d82a5aa08e7d796fdafda54aebfc" + integrity sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA== + dependencies: + bs58 "^4.0.0" + create-hash "^1.1.0" + safe-buffer "^5.1.2" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ== + +buffer@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + +busboy@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893" + integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA== + dependencies: + streamsearch "^1.1.0" + +bytes@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== + +call-bind@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + +caller-callsite@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134" + integrity sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ== + dependencies: + callsites "^2.0.0" + +caller-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-2.0.0.tgz#468f83044e369ab2010fac5f06ceee15bb2cb1f4" + integrity sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A== + dependencies: + caller-callsite "^2.0.0" + +callsites@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" + integrity sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ== + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase@^6.0.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +catering@^2.1.0, catering@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/catering/-/catering-2.1.1.tgz#66acba06ed5ee28d5286133982a927de9a04b510" + integrity sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w== + +chalk@^2.0.0, chalk@^2.1.0, chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== + +chokidar@3.5.3, chokidar@^3.4.0: + version "3.5.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +ci-info@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" + integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +classic-level@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/classic-level/-/classic-level-1.2.0.tgz#2d52bdec8e7a27f534e67fdeb890abef3e643c27" + integrity sha512-qw5B31ANxSluWz9xBzklRWTUAJ1SXIdaVKTVS7HcTGKOAmExx65Wo5BUICW+YGORe2FOUaDghoI9ZDxj82QcFg== + dependencies: + abstract-level "^1.0.2" + catering "^2.1.0" + module-error "^1.0.1" + napi-macros "~2.0.0" + node-gyp-build "^4.3.0" + +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== + +cli-cursor@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" + integrity sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw== + dependencies: + restore-cursor "^2.0.0" + +cli-width@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48" + integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw== + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +command-exists@^1.2.8: + version "1.2.9" + resolved "https://registry.yarnpkg.com/command-exists/-/command-exists-1.2.9.tgz#c50725af3808c8ab0260fd60b01fbfa25b954f69" + integrity sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w== + +command-line-args@^5.1.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-5.2.1.tgz#c44c32e437a57d7c51157696893c5909e9cec42e" + integrity sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg== + dependencies: + array-back "^3.1.0" + find-replace "^3.0.0" + lodash.camelcase "^4.3.0" + typical "^4.0.0" + +command-line-usage@^6.1.0: + version "6.1.3" + resolved "https://registry.yarnpkg.com/command-line-usage/-/command-line-usage-6.1.3.tgz#428fa5acde6a838779dfa30e44686f4b6761d957" + integrity sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw== + dependencies: + array-back "^4.0.2" + chalk "^2.4.2" + table-layout "^1.0.2" + typical "^5.2.0" + +commander@2.18.0: + version "2.18.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.18.0.tgz#2bf063ddee7c7891176981a2cc798e5754bc6970" + integrity sha512-6CYPa+JP2ftfRU2qkDK+UTVeQYosOg/2GbcjIcKPHfinyOLPVGXu/ovN86RP49Re5ndJK1N0kuiidFFuepc4ZQ== + +commander@3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/commander/-/commander-3.0.2.tgz#6837c3fb677ad9933d1cfba42dd14d5117d6b39e" + integrity sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +cookie@^0.4.1: + version "0.4.2" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" + integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== + +cosmiconfig@^5.0.7: + version "5.2.1" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" + integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA== + dependencies: + import-fresh "^2.0.0" + is-directory "^0.3.1" + js-yaml "^3.13.1" + parse-json "^4.0.0" + +crc-32@^1.2.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff" + integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== + +create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.4, create-hmac@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + +cross-spawn@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +debug@4, debug@4.3.4, debug@^4.0.1, debug@^4.1.1, debug@^4.3.1, debug@^4.3.3: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +decamelize@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" + integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== + +deep-extend@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + +deep-is@~0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +depd@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + +diff@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" + integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== + +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +"ds-test@https://github.com/dapphub/ds-test.git#c7a36fb236f298e04edf28e2fee385b80f53945f": + version "0.0.0" + resolved "https://github.com/dapphub/ds-test.git#c7a36fb236f298e04edf28e2fee385b80f53945f" + +elliptic@6.5.4, elliptic@^6.5.2, elliptic@^6.5.4: + version "6.5.4" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" + integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== + dependencies: + bn.js "^4.11.9" + brorand "^1.1.0" + hash.js "^1.0.0" + hmac-drbg "^1.0.1" + inherits "^2.0.4" + minimalistic-assert "^1.0.1" + minimalistic-crypto-utils "^1.0.1" + +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +enquirer@^2.3.0: + version "2.3.6" + resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" + integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== + dependencies: + ansi-colors "^4.1.1" + +env-paths@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" + integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-string-regexp@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +eslint-scope@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" + integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg== + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-utils@^1.3.1: + version "1.4.3" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" + integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== + dependencies: + eslint-visitor-keys "^1.1.0" + +eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" + integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== + +eslint@^5.6.0: + version "5.16.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.16.0.tgz#a1e3ac1aae4a3fbd8296fcf8f7ab7314cbb6abea" + integrity sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg== + dependencies: + "@babel/code-frame" "^7.0.0" + ajv "^6.9.1" + chalk "^2.1.0" + cross-spawn "^6.0.5" + debug "^4.0.1" + doctrine "^3.0.0" + eslint-scope "^4.0.3" + eslint-utils "^1.3.1" + eslint-visitor-keys "^1.0.0" + espree "^5.0.1" + esquery "^1.0.1" + esutils "^2.0.2" + file-entry-cache "^5.0.1" + functional-red-black-tree "^1.0.1" + glob "^7.1.2" + globals "^11.7.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + inquirer "^6.2.2" + js-yaml "^3.13.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.3.0" + lodash "^4.17.11" + minimatch "^3.0.4" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + optionator "^0.8.2" + path-is-inside "^1.0.2" + progress "^2.0.0" + regexpp "^2.0.1" + semver "^5.5.1" + strip-ansi "^4.0.0" + strip-json-comments "^2.0.1" + table "^5.2.3" + text-table "^0.2.0" + +espree@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-5.0.1.tgz#5d6526fa4fc7f0788a5cf75b15f30323e2f81f7a" + integrity sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A== + dependencies: + acorn "^6.0.7" + acorn-jsx "^5.0.0" + eslint-visitor-keys "^1.0.0" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.0.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" + integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +ethereum-cryptography@0.1.3, ethereum-cryptography@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz#8d6143cfc3d74bf79bbd8edecdf29e4ae20dd191" + integrity sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ== + dependencies: + "@types/pbkdf2" "^3.0.0" + "@types/secp256k1" "^4.0.1" + blakejs "^1.1.0" + browserify-aes "^1.2.0" + bs58check "^2.1.2" + create-hash "^1.2.0" + create-hmac "^1.1.7" + hash.js "^1.1.7" + keccak "^3.0.0" + pbkdf2 "^3.0.17" + randombytes "^2.1.0" + safe-buffer "^5.1.2" + scrypt-js "^3.0.0" + secp256k1 "^4.0.1" + setimmediate "^1.0.5" + +ethereum-cryptography@^1.0.3: + version "1.1.2" + resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-1.1.2.tgz#74f2ac0f0f5fe79f012c889b3b8446a9a6264e6d" + integrity sha512-XDSJlg4BD+hq9N2FjvotwUET9Tfxpxc3kWGE2AqUG5vcbeunnbImVk3cj6e/xT3phdW21mE8R5IugU4fspQDcQ== + dependencies: + "@noble/hashes" "1.1.2" + "@noble/secp256k1" "1.6.3" + "@scure/bip32" "1.1.0" + "@scure/bip39" "1.1.0" + +ethereumjs-abi@^0.6.8: + version "0.6.8" + resolved "https://registry.yarnpkg.com/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz#71bc152db099f70e62f108b7cdfca1b362c6fcae" + integrity sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA== + dependencies: + bn.js "^4.11.8" + ethereumjs-util "^6.0.0" + +ethereumjs-util@^6.0.0, ethereumjs-util@^6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz#fcb4e4dd5ceacb9d2305426ab1a5cd93e3163b69" + integrity sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw== + dependencies: + "@types/bn.js" "^4.11.3" + bn.js "^4.11.0" + create-hash "^1.1.2" + elliptic "^6.5.2" + ethereum-cryptography "^0.1.3" + ethjs-util "0.1.6" + rlp "^2.2.3" + +ethjs-util@0.1.6, ethjs-util@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/ethjs-util/-/ethjs-util-0.1.6.tgz#f308b62f185f9fe6237132fb2a9818866a5cd536" + integrity sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w== + dependencies: + is-hex-prefixed "1.0.0" + strip-hex-prefix "1.0.0" + +event-target-shim@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" + integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== + +evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +external-editor@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + +fast-deep-equal@^3.1.1: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-diff@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" + integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +figures@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" + integrity sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA== + dependencies: + escape-string-regexp "^1.0.5" + +file-entry-cache@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" + integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== + dependencies: + flat-cache "^2.0.1" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +find-replace@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-replace/-/find-replace-3.0.0.tgz#3e7e23d3b05167a76f770c9fbd5258b0def68c38" + integrity sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ== + dependencies: + array-back "^3.0.1" + +find-up@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + integrity sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ== + dependencies: + locate-path "^2.0.0" + +flat-cache@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" + integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== + dependencies: + flatted "^2.0.0" + rimraf "2.6.3" + write "1.0.3" + +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== + +flatted@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" + integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== + +follow-redirects@^1.12.1: + version "1.15.2" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" + integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== + +"forge-std@https://github.com/foundry-rs/forge-std.git#37a3fe48c3a4d8239cda93445f0b5e76b1507436": + version "0.0.0" + resolved "https://github.com/foundry-rs/forge-std.git#37a3fe48c3a4d8239cda93445f0b5e76b1507436" + +fp-ts@1.19.3: + version "1.19.3" + resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-1.19.3.tgz#261a60d1088fbff01f91256f91d21d0caaaaa96f" + integrity sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg== + +fp-ts@^1.0.0: + version "1.19.5" + resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-1.19.5.tgz#3da865e585dfa1fdfd51785417357ac50afc520a" + integrity sha512-wDNqTimnzs8QqpldiId9OavWK2NptormjXnRJTQecNjzwfyp6P/8s/zG8e4h3ja3oqkKaY72UlTjQYt/1yXf9A== + +fs-extra@^0.30.0: + version "0.30.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" + integrity sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + klaw "^1.0.0" + path-is-absolute "^1.0.0" + rimraf "^2.2.8" + +fs-extra@^7.0.0, fs-extra@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" + integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.0.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.0.tgz#7ad1dc0535f3a2904bba075772763e5051f6d05f" + integrity sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.3" + +glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob@7.1.7: + version "7.1.7" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" + integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.1.2, glob@^7.1.3: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + 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" + +globals@^11.7.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9: + version "4.2.10" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" + integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== + +handlebars@^4.7.7: + version "4.7.7" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" + integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA== + dependencies: + minimist "^1.2.5" + neo-async "^2.6.0" + source-map "^0.6.1" + wordwrap "^1.0.0" + optionalDependencies: + uglify-js "^3.1.4" + +hardhat@^2.10.1: + version "2.12.6" + resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.12.6.tgz#ea3c058bbd81850867389d10f76037cfa52a0019" + integrity sha512-0Ent1O5DsPgvaVb5sxEgsQ3bJRt/Ex92tsoO+xjoNH2Qc4bFmhI5/CHVlFikulalxOPjNmw5XQ2vJFuVQFESAA== + dependencies: + "@ethersproject/abi" "^5.1.2" + "@metamask/eth-sig-util" "^4.0.0" + "@nomicfoundation/ethereumjs-block" "^4.0.0" + "@nomicfoundation/ethereumjs-blockchain" "^6.0.0" + "@nomicfoundation/ethereumjs-common" "^3.0.0" + "@nomicfoundation/ethereumjs-evm" "^1.0.0" + "@nomicfoundation/ethereumjs-rlp" "^4.0.0" + "@nomicfoundation/ethereumjs-statemanager" "^1.0.0" + "@nomicfoundation/ethereumjs-trie" "^5.0.0" + "@nomicfoundation/ethereumjs-tx" "^4.0.0" + "@nomicfoundation/ethereumjs-util" "^8.0.0" + "@nomicfoundation/ethereumjs-vm" "^6.0.0" + "@nomicfoundation/solidity-analyzer" "^0.1.0" + "@sentry/node" "^5.18.1" + "@types/bn.js" "^5.1.0" + "@types/lru-cache" "^5.1.0" + abort-controller "^3.0.0" + adm-zip "^0.4.16" + aggregate-error "^3.0.0" + ansi-escapes "^4.3.0" + chalk "^2.4.2" + chokidar "^3.4.0" + ci-info "^2.0.0" + debug "^4.1.1" + enquirer "^2.3.0" + env-paths "^2.2.0" + ethereum-cryptography "^1.0.3" + ethereumjs-abi "^0.6.8" + find-up "^2.1.0" + fp-ts "1.19.3" + fs-extra "^7.0.1" + glob "7.2.0" + immutable "^4.0.0-rc.12" + io-ts "1.10.4" + keccak "^3.0.2" + lodash "^4.17.11" + mnemonist "^0.38.0" + mocha "^10.0.0" + p-map "^4.0.0" + qs "^6.7.0" + raw-body "^2.4.1" + resolve "1.17.0" + semver "^6.3.0" + solc "0.7.3" + source-map-support "^0.5.13" + stacktrace-parser "^0.1.10" + tsort "0.0.1" + undici "^5.14.0" + uuid "^8.3.2" + ws "^7.4.6" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +hash-base@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" + integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== + dependencies: + inherits "^2.0.4" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +he@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +hmac-drbg@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== + dependencies: + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" + +https-proxy-agent@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" + integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== + dependencies: + agent-base "6" + debug "4" + +iconv-lite@0.4.24, iconv-lite@^0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ieee754@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== + +immutable@^4.0.0-rc.12: + version "4.2.2" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.2.2.tgz#2da9ff4384a4330c36d4d1bc88e90f9e0b0ccd16" + integrity sha512-fTMKDwtbvO5tldky9QZ2fMX7slR0mYpY5nbnFWYp0fOzDhHqhgIw9KoYgxLWsoNTS9ZHGauHj18DTyEw6BK3Og== + +import-fresh@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" + integrity sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg== + dependencies: + caller-path "^2.0.0" + resolve-from "^3.0.0" + +import-fresh@^3.0.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inquirer@^6.2.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.2.tgz#ad50942375d036d327ff528c08bd5fab089928ca" + integrity sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ== + dependencies: + ansi-escapes "^3.2.0" + chalk "^2.4.2" + cli-cursor "^2.1.0" + cli-width "^2.0.0" + external-editor "^3.0.3" + figures "^2.0.0" + lodash "^4.17.12" + mute-stream "0.0.7" + run-async "^2.2.0" + rxjs "^6.4.0" + string-width "^2.1.0" + strip-ansi "^5.1.0" + through "^2.3.6" + +io-ts@1.10.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/io-ts/-/io-ts-1.10.4.tgz#cd5401b138de88e4f920adbcb7026e2d1967e6e2" + integrity sha512-b23PteSnYXSONJ6JQXRAlvJhuw8KOtkqa87W4wDtvMrud/DTJd5X+NpOOI+O/zZwVq6v0VLAaJ+1EDViKEuN9g== + dependencies: + fp-ts "^1.0.0" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-buffer@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" + integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== + +is-directory@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" + integrity sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw== + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-hex-prefixed@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz#7d8d37e6ad77e5d127148913c573e082d777f554" + integrity sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA== + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-plain-obj@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +js-sha3@0.8.0, js-sha3@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" + integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +js-yaml@^3.12.0, js-yaml@^3.13.0, js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +json-parse-better-errors@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +jsonc-parser@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76" + integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w== + +jsonfile@^2.1.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" + integrity sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw== + optionalDependencies: + graceful-fs "^4.1.6" + +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== + optionalDependencies: + graceful-fs "^4.1.6" + +keccak@^3.0.0, keccak@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/keccak/-/keccak-3.0.3.tgz#4bc35ad917be1ef54ff246f904c2bbbf9ac61276" + integrity sha512-JZrLIAJWuZxKbCilMpNz5Vj7Vtb4scDG3dMXLOsbzBmQGyjwE61BbW7bJkfKKCShXiQZt3T6sBgALRtmd+nZaQ== + dependencies: + node-addon-api "^2.0.0" + node-gyp-build "^4.2.0" + readable-stream "^3.6.0" + +klaw@^1.0.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" + integrity sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw== + optionalDependencies: + graceful-fs "^4.1.9" + +level-supports@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/level-supports/-/level-supports-4.0.1.tgz#431546f9d81f10ff0fea0e74533a0e875c08c66a" + integrity sha512-PbXpve8rKeNcZ9C1mUicC9auIYFyGpkV9/i6g76tLgANwWhtG2v7I4xNBUlkn3lE2/dZF3Pi0ygYGtLc4RXXdA== + +level-transcoder@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/level-transcoder/-/level-transcoder-1.0.1.tgz#f8cef5990c4f1283d4c86d949e73631b0bc8ba9c" + integrity sha512-t7bFwFtsQeD8cl8NIoQ2iwxA0CL/9IFw7/9gAjOonH0PWTTiRfY7Hq+Ejbsxh86tXobDQ6IOiddjNYIfOBs06w== + dependencies: + buffer "^6.0.3" + module-error "^1.0.1" + +level@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/level/-/level-8.0.0.tgz#41b4c515dabe28212a3e881b61c161ffead14394" + integrity sha512-ypf0jjAk2BWI33yzEaaotpq7fkOPALKAgDBxggO6Q9HGX2MRXn0wbP1Jn/tJv1gtL867+YOjOB49WaUF3UoJNQ== + dependencies: + browser-level "^1.0.1" + classic-level "^1.2.0" + +levn@^0.3.0, levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA== + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA== + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== + +lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.16: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +log-symbols@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +lru_map@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd" + integrity sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ== + +lunr@^2.3.9: + version "2.3.9" + resolved "https://registry.yarnpkg.com/lunr/-/lunr-2.3.9.tgz#18b123142832337dd6e964df1a5a7707b25d35e1" + integrity sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow== + +make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +marked@^4.2.5: + version "4.2.12" + resolved "https://registry.yarnpkg.com/marked/-/marked-4.2.12.tgz#d69a64e21d71b06250da995dcd065c11083bebb5" + integrity sha512-yr8hSKa3Fv4D3jdZmtMMPghgVt6TWbk86WQaWhDloQjRSQhMMYCAro7jP7VDJrjjdV8pxVxMssXS8B8Y5DZ5aw== + +mcl-wasm@^0.7.1: + version "0.7.9" + resolved "https://registry.yarnpkg.com/mcl-wasm/-/mcl-wasm-0.7.9.tgz#c1588ce90042a8700c3b60e40efb339fc07ab87f" + integrity sha512-iJIUcQWA88IJB/5L15GnJVnSQJmf/YaxxV6zRavv83HILHaJQb6y0iFyDMdDO0gN8X37tdxmAOrH/P8B6RB8sQ== + +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +memory-level@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/memory-level/-/memory-level-1.0.0.tgz#7323c3fd368f9af2f71c3cd76ba403a17ac41692" + integrity sha512-UXzwewuWeHBz5krr7EvehKcmLFNoXxGcvuYhC41tRnkrTbJohtS7kVn9akmgirtRygg+f7Yjsfi8Uu5SGSQ4Og== + dependencies: + abstract-level "^1.0.0" + functional-red-black-tree "^1.0.1" + module-error "^1.0.1" + +memorystream@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" + integrity sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw== + +mimic-fn@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== + +minimatch@5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.0.1.tgz#fb9022f7528125187c92bd9e9b6366be1cf3415b" + integrity sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^3.0.4, minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^5.1.2: + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + +minimist@^1.2.5, minimist@^1.2.6: + version "1.2.7" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18" + integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g== + +mkdirp@^0.5.1: + version "0.5.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== + dependencies: + minimist "^1.2.6" + +mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + +mnemonist@^0.38.0: + version "0.38.5" + resolved "https://registry.yarnpkg.com/mnemonist/-/mnemonist-0.38.5.tgz#4adc7f4200491237fe0fa689ac0b86539685cade" + integrity sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg== + dependencies: + obliterator "^2.0.0" + +mocha@^10.0.0: + version "10.2.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.2.0.tgz#1fd4a7c32ba5ac372e03a17eef435bd00e5c68b8" + integrity sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg== + dependencies: + ansi-colors "4.1.1" + browser-stdout "1.3.1" + chokidar "3.5.3" + debug "4.3.4" + diff "5.0.0" + escape-string-regexp "4.0.0" + find-up "5.0.0" + glob "7.2.0" + he "1.2.0" + js-yaml "4.1.0" + log-symbols "4.1.0" + minimatch "5.0.1" + ms "2.1.3" + nanoid "3.3.3" + serialize-javascript "6.0.0" + strip-json-comments "3.1.1" + supports-color "8.1.1" + workerpool "6.2.1" + yargs "16.2.0" + yargs-parser "20.2.4" + yargs-unparser "2.0.0" + +module-error@^1.0.1, module-error@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/module-error/-/module-error-1.0.2.tgz#8d1a48897ca883f47a45816d4fb3e3c6ba404d86" + integrity sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +mute-stream@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" + integrity sha512-r65nCZhrbXXb6dXOACihYApHw2Q6pV0M3V0PSxd74N0+D8nzAdEAITq2oAjA1jVnKI+tGvEBUpqiMh0+rW6zDQ== + +nanoid@3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25" + integrity sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w== + +napi-macros@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/napi-macros/-/napi-macros-2.0.0.tgz#2b6bae421e7b96eb687aa6c77a7858640670001b" + integrity sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +neo-async@^2.6.0: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + +node-addon-api@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32" + integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA== + +node-gyp-build@^4.2.0, node-gyp-build@^4.3.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.6.0.tgz#0c52e4cbf54bbd28b709820ef7b6a3c2d6209055" + integrity sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ== + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +object-inspect@^1.9.0: + version "1.12.3" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" + integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== + +obliterator@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/obliterator/-/obliterator-2.0.4.tgz#fa650e019b2d075d745e44f1effeb13a2adbe816" + integrity sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ== + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +onetime@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + integrity sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ== + dependencies: + mimic-fn "^1.0.0" + +optionator@^0.8.2: + version "0.8.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.6" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + word-wrap "~1.2.3" + +os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== + +p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== + dependencies: + p-try "^1.0.0" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg== + dependencies: + p-limit "^1.1.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +p-map@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" + integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== + dependencies: + aggregate-error "^3.0.0" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww== + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-json@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + integrity sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw== + dependencies: + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-is-inside@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + integrity sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w== + +path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw== + +path-parse@^1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +pbkdf2@^3.0.17: + version "3.1.2" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" + integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +picomatch@^2.0.4, picomatch@^2.2.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w== + +prettier-plugin-solidity@^1.0.0-beta.19: + version "1.1.1" + resolved "https://registry.yarnpkg.com/prettier-plugin-solidity/-/prettier-plugin-solidity-1.1.1.tgz#4d3375b85f97812ffcbe48d5a8b3fe914d69c91f" + integrity sha512-uD24KO26tAHF+zMN2nt1OUzfknzza5AgxjogQQrMLZc7j8xiQrDoNWNeOlfFC0YLTwo12CLD10b9niLyP6AqXg== + dependencies: + "@solidity-parser/parser" "^0.14.5" + semver "^7.3.8" + solidity-comments-extractor "^0.0.7" + +prettier@^1.14.3: + version "1.19.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" + integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== + +prettier@^2.3.1, prettier@^2.6.2: + version "2.8.3" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.3.tgz#ab697b1d3dd46fb4626fbe2f543afe0cc98d8632" + integrity sha512-tJ/oJ4amDihPoufT5sM0Z1SKEuKay8LfVAMlbbhnnkvt6BUserZylqo2PN+p9KeljLr0OHa2rXHU1T8reeoTrw== + +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + +punycode@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" + integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== + +qs@^6.7.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== + dependencies: + side-channel "^1.0.4" + +queue-microtask@^1.2.2, queue-microtask@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +raw-body@^2.4.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" + integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" + +readable-stream@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +reduce-flatten@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/reduce-flatten/-/reduce-flatten-2.0.0.tgz#734fd84e65f375d7ca4465c69798c25c9d10ae27" + integrity sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w== + +regexpp@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" + integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +require-from-string@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +resolve-from@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" + integrity sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw== + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve@1.17.0: + version "1.17.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" + integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== + dependencies: + path-parse "^1.0.6" + +restore-cursor@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" + integrity sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q== + dependencies: + onetime "^2.0.0" + signal-exit "^3.0.2" + +rimraf@2.6.3: + version "2.6.3" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" + integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== + dependencies: + glob "^7.1.3" + +rimraf@^2.2.8: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +rlp@^2.2.3: + version "2.2.7" + resolved "https://registry.yarnpkg.com/rlp/-/rlp-2.2.7.tgz#33f31c4afac81124ac4b283e2bd4d9720b30beaf" + integrity sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ== + dependencies: + bn.js "^5.2.0" + +run-async@^2.2.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" + integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== + +run-parallel-limit@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz#be80e936f5768623a38a963262d6bef8ff11e7ba" + integrity sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw== + dependencies: + queue-microtask "^1.2.2" + +rustbn.js@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/rustbn.js/-/rustbn.js-0.2.0.tgz#8082cb886e707155fd1cb6f23bd591ab8d55d0ca" + integrity sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA== + +rxjs@^6.4.0: + version "6.6.7" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" + integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== + dependencies: + tslib "^1.9.0" + +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +scrypt-js@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-3.0.1.tgz#d314a57c2aef69d1ad98a138a21fe9eafa9ee312" + integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== + +secp256k1@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-4.0.3.tgz#c4559ecd1b8d3c1827ed2d1b94190d69ce267303" + integrity sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA== + dependencies: + elliptic "^6.5.4" + node-addon-api "^2.0.0" + node-gyp-build "^4.2.0" + +semver@^5.5.0, semver@^5.5.1: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +semver@^7.3.8: + version "7.3.8" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" + integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== + dependencies: + lru-cache "^6.0.0" + +serialize-javascript@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" + integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== + dependencies: + randombytes "^2.1.0" + +setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg== + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ== + +shiki@^0.12.1: + version "0.12.1" + resolved "https://registry.yarnpkg.com/shiki/-/shiki-0.12.1.tgz#26fce51da12d055f479a091a5307470786f300cd" + integrity sha512-aieaV1m349rZINEBkjxh2QbBvFFQOlgqYTNtCal82hHj4dDZ76oMlQIX+C7ryerBTDiga3e5NfH6smjdJ02BbQ== + dependencies: + jsonc-parser "^3.2.0" + vscode-oniguruma "^1.7.0" + vscode-textmate "^8.0.0" + +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +signal-exit@^3.0.2: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +slice-ansi@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" + integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== + dependencies: + ansi-styles "^3.2.0" + astral-regex "^1.0.0" + is-fullwidth-code-point "^2.0.0" + +solc@0.7.3: + version "0.7.3" + resolved "https://registry.yarnpkg.com/solc/-/solc-0.7.3.tgz#04646961bd867a744f63d2b4e3c0701ffdc7d78a" + integrity sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA== + dependencies: + command-exists "^1.2.8" + commander "3.0.2" + follow-redirects "^1.12.1" + fs-extra "^0.30.0" + js-sha3 "0.8.0" + memorystream "^0.3.1" + require-from-string "^2.0.0" + semver "^5.5.0" + tmp "0.0.33" + +solhint@^3.3.7: + version "3.3.8" + resolved "https://registry.yarnpkg.com/solhint/-/solhint-3.3.8.tgz#b1773c881cfaf0b5008c78ad658a69603d3fa051" + integrity sha512-TkYyJ6uUJCaiqRKuhHhFuoAoyco9Ia+RDKhl3usjG/rkaNk8/LdLRla2Xln7MVdBTaPKNAU8ezTRSit50Yy4qw== + dependencies: + "@solidity-parser/parser" "^0.14.5" + ajv "^6.6.1" + antlr4 "4.7.1" + ast-parents "0.0.1" + chalk "^2.4.2" + commander "2.18.0" + cosmiconfig "^5.0.7" + eslint "^5.6.0" + fast-diff "^1.1.2" + glob "^7.1.3" + ignore "^4.0.6" + js-yaml "^3.12.0" + lodash "^4.17.11" + semver "^6.3.0" + optionalDependencies: + prettier "^1.14.3" + +solidity-ast@^0.4.38: + version "0.4.44" + resolved "https://registry.yarnpkg.com/solidity-ast/-/solidity-ast-0.4.44.tgz#dd6732bd65bb1d01777fc537de99cbb3d4e0089d" + integrity sha512-Ct3ppqWS0uTWNYxM2cgruUeWYzqYmeikANsCHgGBnMjAMsqONgqnYrlpifQxNFwXOPHD3vZQLmCjaYnQ+i3eQA== + +solidity-comments-extractor@^0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz#99d8f1361438f84019795d928b931f4e5c39ca19" + integrity sha512-wciNMLg/Irp8OKGrh3S2tfvZiZ0NEyILfcRCXCD4mp7SgK/i9gzLfhY2hY7VMCQJ3kH9UB9BzNdibIVMchzyYw== + +solidity-docgen@^0.6.0-beta.22: + version "0.6.0-beta.34" + resolved "https://registry.yarnpkg.com/solidity-docgen/-/solidity-docgen-0.6.0-beta.34.tgz#f1766b13ea864ea71b8e727796d30a69ea90014a" + integrity sha512-igdGrkg8gT1jn+B2NwzjEtSf+7NTrSi/jz88zO7MZWgETmcWbXaxgAsQP4BQeC4YFeH0Pie1NsLP7+9qDgvFtA== + dependencies: + handlebars "^4.7.7" + solidity-ast "^0.4.38" + +source-map-support@^0.5.13: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0, source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + +stacktrace-parser@^0.1.10: + version "0.1.10" + resolved "https://registry.yarnpkg.com/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz#29fb0cae4e0d0b85155879402857a1639eb6051a" + integrity sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg== + dependencies: + type-fest "^0.7.1" + +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== + +streamsearch@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" + integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== + +string-format@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/string-format/-/string-format-2.0.0.tgz#f2df2e7097440d3b65de31b6d40d54c96eaffb9b" + integrity sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA== + +string-width@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string-width@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +string-width@^4.1.0, string-width@^4.2.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow== + dependencies: + ansi-regex "^3.0.0" + +strip-ansi@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-hex-prefix@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz#0c5f155fef1151373377de9dbb588da05500e36f" + integrity sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A== + dependencies: + is-hex-prefixed "1.0.0" + +strip-json-comments@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +strip-json-comments@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== + +supports-color@8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +table-layout@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/table-layout/-/table-layout-1.0.2.tgz#c4038a1853b0136d63365a734b6931cf4fad4a04" + integrity sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A== + dependencies: + array-back "^4.0.1" + deep-extend "~0.6.0" + typical "^5.2.0" + wordwrapjs "^4.0.0" + +table@^5.2.3: + version "5.4.6" + resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" + integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== + dependencies: + ajv "^6.10.2" + lodash "^4.17.14" + slice-ansi "^2.1.0" + string-width "^3.0.0" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +through@^2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== + +tmp@0.0.33, tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + +ts-command-line-args@^2.2.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/ts-command-line-args/-/ts-command-line-args-2.4.2.tgz#b4815b23c35f8a0159d4e69e01012d95690bc448" + integrity sha512-mJLQQBOdyD4XI/ZWQY44PIdYde47JhV2xl380O7twPkTQ+Y5vFDHsk8LOeXKuz7dVY5aDCfAzRarNfSqtKOkQQ== + dependencies: + "@morgan-stanley/ts-mocking-bird" "^0.6.2" + chalk "^4.1.0" + command-line-args "^5.1.1" + command-line-usage "^6.1.0" + string-format "^2.0.0" + +ts-essentials@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-7.0.3.tgz#686fd155a02133eedcc5362dc8b5056cde3e5a38" + integrity sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ== + +ts-node@10.7: + version "10.7.0" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.7.0.tgz#35d503d0fab3e2baa672a0e94f4b40653c2463f5" + integrity sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A== + dependencies: + "@cspotcode/source-map-support" "0.7.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.0" + yn "3.1.1" + +tslib@^1.9.0, tslib@^1.9.3: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tsort@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/tsort/-/tsort-0.0.1.tgz#e2280f5e817f8bf4275657fd0f9aebd44f5a2786" + integrity sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw== + +tweetnacl-util@^0.15.1: + version "0.15.1" + resolved "https://registry.yarnpkg.com/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz#b80fcdb5c97bcc508be18c44a4be50f022eea00b" + integrity sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw== + +tweetnacl@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" + integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg== + dependencies: + prelude-ls "~1.1.2" + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +type-fest@^0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.7.1.tgz#8dda65feaf03ed78f0a3f9678f1869147f7c5c48" + integrity sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg== + +typechain@^8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/typechain/-/typechain-8.1.1.tgz#9c2e8012c2c4c586536fc18402dcd7034c4ff0bd" + integrity sha512-uF/sUvnXTOVF2FHKhQYnxHk4su4JjZR8vr4mA2mBaRwHTbwh0jIlqARz9XJr1tA0l7afJGvEa1dTSi4zt039LQ== + dependencies: + "@types/prettier" "^2.1.1" + debug "^4.3.1" + fs-extra "^7.0.0" + glob "7.1.7" + js-sha3 "^0.8.0" + lodash "^4.17.15" + mkdirp "^1.0.4" + prettier "^2.3.1" + ts-command-line-args "^2.2.0" + ts-essentials "^7.0.1" + +typedoc@^0.23.10: + version "0.23.24" + resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.23.24.tgz#01cf32c09f2c19362e72a9ce1552d6e5b48c4fef" + integrity sha512-bfmy8lNQh+WrPYcJbtjQ6JEEsVl/ce1ZIXyXhyW+a1vFrjO39t6J8sL/d6FfAGrJTc7McCXgk9AanYBSNvLdIA== + dependencies: + lunr "^2.3.9" + marked "^4.2.5" + minimatch "^5.1.2" + shiki "^0.12.1" + +typical@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4" + integrity sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw== + +typical@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/typical/-/typical-5.2.0.tgz#4daaac4f2b5315460804f0acf6cb69c52bb93066" + integrity sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg== + +uglify-js@^3.1.4: + version "3.17.4" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.4.tgz#61678cf5fa3f5b7eb789bb345df29afb8257c22c" + integrity sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g== + +undici@^5.14.0: + version "5.16.0" + resolved "https://registry.yarnpkg.com/undici/-/undici-5.16.0.tgz#6b64f9b890de85489ac6332bd45ca67e4f7d9943" + integrity sha512-KWBOXNv6VX+oJQhchXieUznEmnJMqgXMbs0xxH2t8q/FUAWSJvOSr/rMaZKnX5RIVq7JDn0JbP4BOnKG2SGXLQ== + dependencies: + busboy "^1.6.0" + +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + +unpipe@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +util-deprecate@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +uuid@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b" + integrity sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg== + +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +v8-compile-cache-lib@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" + integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== + +vscode-oniguruma@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz#439bfad8fe71abd7798338d1cd3dc53a8beea94b" + integrity sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA== + +vscode-textmate@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-8.0.0.tgz#2c7a3b1163ef0441097e0b5d6389cd5504b59e5d" + integrity sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg== + +which@^1.2.9: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +word-wrap@~1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + +wordwrap@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== + +wordwrapjs@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/wordwrapjs/-/wordwrapjs-4.0.1.tgz#d9790bccfb110a0fc7836b5ebce0937b37a8b98f" + integrity sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA== + dependencies: + reduce-flatten "^2.0.0" + typical "^5.2.0" + +workerpool@6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343" + integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +write@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" + integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== + dependencies: + mkdirp "^0.5.1" + +ws@^7.4.6: + version "7.5.9" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" + integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yargs-parser@20.2.4: + version "20.2.4" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" + integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== + +yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs-unparser@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" + integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== + dependencies: + camelcase "^6.0.0" + decamelize "^4.0.0" + flat "^5.0.2" + is-plain-obj "^2.1.0" + +yargs@16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== diff --git a/yarn.lock b/yarn.lock index 4406ece53c..cbf2439125 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4270,6 +4270,16 @@ ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.6, ajv@^6.6.1, ajv json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@^8.0.1: + version "8.12.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" + integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + ajv@^8.11.0: version "8.11.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f" @@ -10840,6 +10850,11 @@ lodash.templatesettings@^4.0.0: dependencies: lodash._reinterpolate "^3.0.0" +lodash.truncate@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" + integrity sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw== + lodash@4.17.21, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21, lodash@^4.3.0, lodash@^4.7.0: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" @@ -14396,6 +14411,17 @@ table@^5.2.3: slice-ansi "^2.1.0" string-width "^3.0.0" +table@^6.8.1: + version "6.8.1" + resolved "https://registry.yarnpkg.com/table/-/table-6.8.1.tgz#ea2b71359fe03b017a5fbc296204471158080bdf" + integrity sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA== + 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" + tar-fs@^2.0.0, tar-fs@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784"